commit 6758bfef36967d4c9b3d63ae834d11ee1c403d03 Author: upstream Date: Fri Sep 4 04:49:30 2026 +0200 Upstream avoidwork/filesize.js state of the touched files before 15b1dba9c6 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9cc1c37 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1631 @@ +{ + "name": "filesize", + "version": "11.0.23", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "filesize", + "version": "11.0.23", + "license": "BSD-3-Clause", + "devDependencies": { + "@rollup/plugin-terser": "^1.0.0", + "auto-changelog": "^2.5.0", + "husky": "^9.1.7", + "oxfmt": "^0.65.0", + "oxlint": "^1.57.0", + "rollup": "^4.52.0" + }, + "engines": { + "node": ">= 10.8.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@oxfmt/binding-android-arm-eabi": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.65.0.tgz", + "integrity": "sha512-M10Gs1SSpTNI6ahGx3M/OlIdUF4hkaP6OgUb+MS79t/Pgflk3r1nW5gPFqsZGUAXg0H1AfANT9AvLdBSTIhZKg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-android-arm64": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.65.0.tgz", + "integrity": "sha512-6DXH5sftNlaHpWJG50hFMF+Qxtq5D2TmahvcDPxWNcGIf8qrC9Y0YgHYcYZ2hlWzaccKXh/f3GcssH8vtkl4JA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-darwin-arm64": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.65.0.tgz", + "integrity": "sha512-K9m7lr53pcOLETNsC88sWes/GWHUGjZyHx95UhYcSXy0r30haLdeXlSufSenEAtoLaW753WN8/l4M7GYcRt6cg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-darwin-x64": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.65.0.tgz", + "integrity": "sha512-sTNwIx1gre3MyiHOPLu7IGW4UyMScYL4DTmJT01p4vzB0En+OJUQz6KuH8t0PpsClRSaMuY3b0QmtoPItfO8Lg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-freebsd-x64": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.65.0.tgz", + "integrity": "sha512-lYZMVIiIpnjGu5hJb2jxA8NYQ/e0OTGuaiAf4dqlGPNnPmUTu23FZRMltmjro/KkQm1uE4NT4n5yJ2zWmKcpfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.65.0.tgz", + "integrity": "sha512-gIdXFAt/bURnjxuoedDEWdZ0PEWEmdDcm8qdpoFYYvW3QMk/5D4vUaH4mlMeRpeTdST4izUgHVO6RawQ4QulJw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm-musleabihf": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.65.0.tgz", + "integrity": "sha512-jJVyADto7gA2AaX5qAjAexrxx9PJQaKWOe8PICE7yKMbjBRyOHcmj9TtVJ+MZYDUQ3hodU0AcoTj0jFQ1W4C6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm64-gnu": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.65.0.tgz", + "integrity": "sha512-p3RFkB+u7u+8up99b/NEcI1hdpLDiGgJYNwDorB60n7eH+eKposAKuMBxx+NqB3b+sJP4CZmYDh9G7X62tUsKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-arm64-musl": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.65.0.tgz", + "integrity": "sha512-5Prb0uFzJHr+OUD/qS/TmU526wD+PaHDsm3KoRiUXbMIDpTSErjeQYkK3OQeshAvD/PuLa9WGEi9WPajjdOZJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-ppc64-gnu": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.65.0.tgz", + "integrity": "sha512-S8svxTp81obnF3admN9yd+u2rOYXtyzThLGBTg1PY6TPtGcC09BaaXLQD+TBSMa7yvqhCDZ8DFri+S/yG60qCg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-riscv64-gnu": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.65.0.tgz", + "integrity": "sha512-WtXBr75G/h2qOHy8SiGtC1R6aS3jt4mE52v1D8AtwMXIgoOmSNP9lKvbSaTRoL0e5wsMPoi6T72QWDYPu+S+nA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-riscv64-musl": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.65.0.tgz", + "integrity": "sha512-YwSLVvpaz4o/nv/miiPEBJz+eJ+VmbgNIrao6RccK9ce+L5EA8wP+ZD0uFeq6wKOza6zoWv/dR0sj6lip6R3EA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-s390x-gnu": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.65.0.tgz", + "integrity": "sha512-XQTPqgvyrgkKcFq+Tp2eK6JS7sqqJ+nRmy2Fav4j3I+i4dJoPJm7YwEdoeSDX9xkqj9jZ/lWfF3bXUWztIrn6A==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-x64-gnu": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.65.0.tgz", + "integrity": "sha512-cjZlx6S/VkeCNWCbwZriTnLnZeTcV3DEyeRGSw/2wwLP9viq+C0bJ4bC1k/ZLkFxDcB1lUgSasPkYGP1bdraOg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-linux-x64-musl": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.65.0.tgz", + "integrity": "sha512-2azCjxdLtK4zCcIOU1dlXlU0xxfbPi6EjwWx7Ac7teWPidIIDOcIhudup83xNCKYhtqeVd/gaVDOxbUq4syXWA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-openharmony-arm64": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.65.0.tgz", + "integrity": "sha512-KXQ7xi1e/voP0IQaw6fG6XY4Z5+Llf1XmRSZS1t7pVFCecFJ0iXaboKmVwjFtp5MLlT5iWQrJ2U1C3GJdZ2u+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-arm64-msvc": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.65.0.tgz", + "integrity": "sha512-2FbbjG5jEqLSLKVJwBap84uJfpn5Y5A53KEO0aUNr+zeiRB9nyPUIFMcSbZVMFLitfBytFWRNngozXYjb6Rsbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-ia32-msvc": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.65.0.tgz", + "integrity": "sha512-LJ+ZacAPSjegDOnSLyA1TMWAhdDrsK4el3REdr1oL2UtVBCMhO2II/Sb3cEW6mF2MfLhl8hDNCSvc7KSbgk3LQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxfmt/binding-win32-x64-msvc": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.65.0.tgz", + "integrity": "sha512-higu9cWEO6XXFzATD1jf0mCK34rNfN2H9JrJie7QB1IhleVpTh0QlLH9Ip2C1H/Nd5n0v5pvRtC+5R0uE4HpVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.80.0.tgz", + "integrity": "sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.80.0.tgz", + "integrity": "sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.80.0.tgz", + "integrity": "sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.80.0.tgz", + "integrity": "sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.80.0.tgz", + "integrity": "sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.80.0.tgz", + "integrity": "sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.80.0.tgz", + "integrity": "sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.80.0.tgz", + "integrity": "sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.80.0.tgz", + "integrity": "sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.80.0.tgz", + "integrity": "sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.80.0.tgz", + "integrity": "sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.80.0.tgz", + "integrity": "sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.80.0.tgz", + "integrity": "sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.80.0.tgz", + "integrity": "sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.80.0.tgz", + "integrity": "sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.80.0.tgz", + "integrity": "sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.80.0.tgz", + "integrity": "sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.80.0.tgz", + "integrity": "sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.80.0.tgz", + "integrity": "sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^7.0.3", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.1.tgz", + "integrity": "sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.1.tgz", + "integrity": "sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.1.tgz", + "integrity": "sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.1.tgz", + "integrity": "sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.1.tgz", + "integrity": "sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.1.tgz", + "integrity": "sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.1.tgz", + "integrity": "sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.1.tgz", + "integrity": "sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.1.tgz", + "integrity": "sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.1.tgz", + "integrity": "sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.1.tgz", + "integrity": "sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.1.tgz", + "integrity": "sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.1.tgz", + "integrity": "sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.1.tgz", + "integrity": "sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.1.tgz", + "integrity": "sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.1.tgz", + "integrity": "sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.1.tgz", + "integrity": "sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.1.tgz", + "integrity": "sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.1.tgz", + "integrity": "sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.1.tgz", + "integrity": "sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.1.tgz", + "integrity": "sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.1.tgz", + "integrity": "sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.1.tgz", + "integrity": "sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.1.tgz", + "integrity": "sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.1.tgz", + "integrity": "sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/auto-changelog": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.6.0.tgz", + "integrity": "sha512-jJgUkuWXQ7fPLPXOMQk/XSSmy7KvzpzhjJa6w660dq1KTEez/GW2CPckBra3jMMMMpcwxp84bOslo29qRCewzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^7.2.0", + "handlebars": "^4.7.9", + "import-cwd": "^3.0.0", + "parse-github-url": "^1.0.4", + "semver": "^7.8.1" + }, + "bin": { + "auto-changelog": "src/index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-from": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/oxfmt": { + "version": "0.65.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.65.0.tgz", + "integrity": "sha512-SgS5VgnP42T0zl3zWD+xoH8FCqg1SAFnSRoOT/qeoa6gxcYIqrDMOmcXIg/EWSN92Du4ogB4riuKhKd6Y4CGhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinypool": "2.1.0" + }, + "bin": { + "oxfmt": "bin/oxfmt" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxfmt/binding-android-arm-eabi": "0.65.0", + "@oxfmt/binding-android-arm64": "0.65.0", + "@oxfmt/binding-darwin-arm64": "0.65.0", + "@oxfmt/binding-darwin-x64": "0.65.0", + "@oxfmt/binding-freebsd-x64": "0.65.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.65.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.65.0", + "@oxfmt/binding-linux-arm64-gnu": "0.65.0", + "@oxfmt/binding-linux-arm64-musl": "0.65.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.65.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.65.0", + "@oxfmt/binding-linux-riscv64-musl": "0.65.0", + "@oxfmt/binding-linux-s390x-gnu": "0.65.0", + "@oxfmt/binding-linux-x64-gnu": "0.65.0", + "@oxfmt/binding-linux-x64-musl": "0.65.0", + "@oxfmt/binding-openharmony-arm64": "0.65.0", + "@oxfmt/binding-win32-arm64-msvc": "0.65.0", + "@oxfmt/binding-win32-ia32-msvc": "0.65.0", + "@oxfmt/binding-win32-x64-msvc": "0.65.0" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/oxlint": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.80.0.tgz", + "integrity": "sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.80.0", + "@oxlint/binding-android-arm64": "1.80.0", + "@oxlint/binding-darwin-arm64": "1.80.0", + "@oxlint/binding-darwin-x64": "1.80.0", + "@oxlint/binding-freebsd-x64": "1.80.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.80.0", + "@oxlint/binding-linux-arm-musleabihf": "1.80.0", + "@oxlint/binding-linux-arm64-gnu": "1.80.0", + "@oxlint/binding-linux-arm64-musl": "1.80.0", + "@oxlint/binding-linux-ppc64-gnu": "1.80.0", + "@oxlint/binding-linux-riscv64-gnu": "1.80.0", + "@oxlint/binding-linux-riscv64-musl": "1.80.0", + "@oxlint/binding-linux-s390x-gnu": "1.80.0", + "@oxlint/binding-linux-x64-gnu": "1.80.0", + "@oxlint/binding-linux-x64-musl": "1.80.0", + "@oxlint/binding-openharmony-arm64": "1.80.0", + "@oxlint/binding-win32-arm64-msvc": "1.80.0", + "@oxlint/binding-win32-ia32-msvc": "1.80.0", + "@oxlint/binding-win32-x64-msvc": "1.80.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=7.0.2001", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/parse-github-url": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.4.tgz", + "integrity": "sha512-CEtCOt55fHmd6DpBc/N7H5NC4vJpcquhzzs9Iw2mRj8bVxo1O5TQI5MXKOMO7+yBOqD+5dKCCRK4Kj1KskZc6Q==", + "dev": true, + "license": "MIT", + "bin": { + "parse-github-url": "cli.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/rollup": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.1.tgz", + "integrity": "sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.1", + "@rollup/rollup-android-arm64": "4.63.1", + "@rollup/rollup-darwin-arm64": "4.63.1", + "@rollup/rollup-darwin-x64": "4.63.1", + "@rollup/rollup-freebsd-arm64": "4.63.1", + "@rollup/rollup-freebsd-x64": "4.63.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.1", + "@rollup/rollup-linux-arm-musleabihf": "4.63.1", + "@rollup/rollup-linux-arm64-gnu": "4.63.1", + "@rollup/rollup-linux-arm64-musl": "4.63.1", + "@rollup/rollup-linux-loong64-gnu": "4.63.1", + "@rollup/rollup-linux-loong64-musl": "4.63.1", + "@rollup/rollup-linux-ppc64-gnu": "4.63.1", + "@rollup/rollup-linux-ppc64-musl": "4.63.1", + "@rollup/rollup-linux-riscv64-gnu": "4.63.1", + "@rollup/rollup-linux-riscv64-musl": "4.63.1", + "@rollup/rollup-linux-s390x-gnu": "4.63.1", + "@rollup/rollup-linux-x64-gnu": "4.63.1", + "@rollup/rollup-linux-x64-musl": "4.63.1", + "@rollup/rollup-openbsd-x64": "4.63.1", + "@rollup/rollup-openharmony-arm64": "4.63.1", + "@rollup/rollup-win32-arm64-msvc": "4.63.1", + "@rollup/rollup-win32-ia32-msvc": "4.63.1", + "@rollup/rollup-win32-x64-gnu": "4.63.1", + "@rollup/rollup-win32-x64-msvc": "4.63.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/terser": { + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.14.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", + "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..e4f1c73 --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,489 @@ +import { + ARRAY, + BINARY_POWERS, + BIT, + BITS, + BYTE, + BYTES, + DECIMAL_POWERS, + E, + EMPTY, + EXPONENT, + IEC, + JEDEC, + LOG_10_1000, + LOG_2_1024, + OBJECT, + PERIOD, + S, + SI, + SI_KBIT, + SI_KBYTE, + SPACE, + STRINGS, + ZERO, +} from "./constants.js"; + +// Cached configuration lookup for better performance +const STANDARD_CONFIGS = { + [SI]: { isDecimal: true, ceil: 1000, actualStandard: JEDEC }, + [IEC]: { isDecimal: false, ceil: 1024, actualStandard: IEC }, + [JEDEC]: { isDecimal: false, ceil: 1024, actualStandard: JEDEC }, +}; + +/** + * Optimized base configuration lookup + * @param {string} standard - Standard type + * @param {number} base - Base number + * @returns {Object} Configuration object + */ +export function getBaseConfiguration(standard, base) { + // Use cached lookup table for better performance + if (STANDARD_CONFIGS[standard]) { + return STANDARD_CONFIGS[standard]; + } + + // Base override + if (base === 2) { + return { isDecimal: false, ceil: 1024, actualStandard: IEC }; + } + + // Default + return { isDecimal: true, ceil: 1000, actualStandard: JEDEC }; +} + +/** + * Optimized zero value handling + * @param {number} precision - Precision value + * @param {string} actualStandard - Standard to use + * @param {boolean} bits - Whether to use bits + * @param {Object} symbols - Custom symbols + * @param {boolean} full - Whether to use full form + * @param {Array} fullforms - Custom full forms + * @param {string} output - Output format + * @param {string} spacer - Spacer character + * @param {boolean} pad - Whether to pad decimal places + * @param {number} round - Number of decimal places for padding + * @param {string} [symbol] - Symbol to use (defaults based on bits/standard) + * @returns {string|Array|Object|number} Formatted result + */ +export function handleZeroValue( + precision, + actualStandard, + bits, + symbols, + full, + fullforms, + output, + spacer, + pad, + round, + symbol, +) { + let value; + if (precision > 0) { + value = (0).toPrecision(precision); + } else if (pad && round > 0) { + value = (0).toFixed(round); + } else { + value = 0; + } + + if (output === EXPONENT) { + return 0; + } + + // Set default symbol if not provided + if (!symbol) { + symbol = bits + ? STRINGS.symbol[actualStandard].bits[0] + : STRINGS.symbol[actualStandard].bytes[0]; + } + + // Apply symbol customization + if (symbols[symbol]) { + symbol = symbols[symbol]; + } + + // Apply full form + if (full) { + if (fullforms[0]) { + symbol = fullforms[0]; + } else { + symbol = STRINGS.fullform[actualStandard][0]; + if (bits) { + symbol += BIT; + } else { + symbol += BYTE; + } + } + } + + // Return in requested format + if (output === ARRAY) { + return [value, symbol]; + } + + if (output === OBJECT) { + return { value, symbol, exponent: 0, unit: symbol }; + } + + return value + spacer + symbol; +} + +/** + * Optimized value calculation with bits handling + * @param {number} num - Input number + * @param {number} e - Exponent + * @param {boolean} isDecimal - Whether to use decimal powers + * @param {boolean} bits - Whether to calculate bits + * @param {number} ceil - Ceiling value for auto-increment + * @param {boolean} autoExponent - Whether exponent is auto (-1 or NaN) + * @returns {Object} Object with result and e properties + */ +export function calculateOptimizedValue(num, e, isDecimal, bits, ceil, autoExponent = true) { + let d; + if (isDecimal) { + d = DECIMAL_POWERS[e]; + } else { + d = BINARY_POWERS[e]; + } + let result = num / d; + + if (bits) { + result *= 8; + // Handle auto-increment for bits (only when exponent is auto) + if (autoExponent && result >= ceil && e < 8) { + result /= ceil; + e++; + } + } + + return { result, e }; +} + +/** + * Optimized precision handling with scientific notation correction + * @param {number} value - Current value + * @param {number} precision - Precision to apply + * @param {number} e - Current exponent + * @param {number} num - Original number + * @param {boolean} isDecimal - Whether using decimal base + * @param {boolean} bits - Whether calculating bits + * @param {number} ceil - Ceiling value + * @param {Function} roundingFunc - Rounding function + * @param {number} round - Round value + * @param {number} exponent - Forced exponent (-1 for auto) + * @returns {Object} Object with value and e properties + */ +export function applyPrecisionHandling( + value, + precision, + e, + num, + isDecimal, + bits, + ceil, + roundingFunc, + round, + exponent, +) { + if (typeof value === "string") { + value = parseFloat(value); + } + + let result = value.toPrecision(precision); + + const autoExponent = exponent === -1 || isNaN(exponent); + + // Handle scientific notation by recalculating with incremented exponent + if (result.includes(E) && e < 8 && autoExponent) { + e++; + const { result: valueResult } = calculateOptimizedValue(num, e, isDecimal, bits, ceil); + let p; + if (round > 0) { + p = Math.pow(10, round); + } else { + p = 1; + } + let computed; + if (p === 1) { + computed = roundingFunc(valueResult); + } else { + computed = roundingFunc(valueResult * p) / p; + } + result = computed.toPrecision(precision); + } + + return { value: result, e }; +} + +/** + * Optimized number formatting with locale, separator, and padding + * @param {number|string} value - Value to format + * @param {string|boolean} locale - Locale setting + * @param {Object} localeOptions - Locale options + * @param {string} separator - Custom separator + * @param {boolean} pad - Whether to pad + * @param {number} round - Round value + * @returns {string|number} Formatted value + */ +export function applyNumberFormatting( + value, + locale, + localeOptions, + separator, + pad, + round, + roundingFunc, +) { + let result = value; + + // When padding alongside a locale, let the locale formatter emit the fixed + // number of fraction digits. The manual string padding below cannot tell a + // locale-inserted grouping separator from the decimal separator, so it + // dropped digits (e.g. "1,234,500" became "1,234"). + const localePad = + pad && round > 0 ? { minimumFractionDigits: round, maximumFractionDigits: round } : undefined; + + // Apply locale formatting + if (locale === true) { + result = result.toLocaleString(undefined, localePad); + } else if (locale.length > 0) { + result = result.toLocaleString(locale, { ...localeOptions, ...localePad }); + } else if (separator.length > 0) { + // Round before separator replacement to ensure excess decimal places + // are truncated when pad is also set (fixes padding + separator bug). + if (pad && round > 0) { + const p = Math.pow(10, round); + result = roundingFunc(result * p) / p; + } + result = result.toString().replace(PERIOD, separator); + } + + // Apply padding for the non-locale paths, where the string has a single + // decimal separator and no grouping is inserted. + if (pad && round > 0 && locale !== true && locale.length === 0) { + const resultStr = result.toString(); + const x = separator || PERIOD; + const tmp = resultStr.split(x); + const s = tmp[1] || EMPTY; + + result = `${tmp[0]}${x}${s.padEnd(round, ZERO)}`; + } + + return result; +} + +/** + * Calculates exponent from the input value using pre-computed log values and clamps to supported range + * Also adjusts precision when exponent exceeds the lookup table bounds + * @param {number} num - Input file size in bytes + * @param {number} e - Current exponent value + * @param {number} exponent - Original user-provided exponent option (-1 for auto) + * @param {boolean} isDecimal - Whether to use decimal (SI) base + * @param {number} precision - Current precision value (modified when e > 8) + * @returns {Object} Object with computed e value and possibly adjusted precision + */ +export function calculateExponent(num, e, exponent, isDecimal, precision) { + if (e === -1 || isNaN(e)) { + if (isDecimal) { + e = Math.floor(Math.log(num) / LOG_10_1000); + } else { + e = Math.floor(Math.log(num) / LOG_2_1024); + } + if (e < 0) { + e = 0; + } + } else if (e < 0) { + // A forced exponent below the auto sentinel (-1) has no meaning and + // would otherwise index the power-of-ten/two lookup tables out of + // bounds (producing NaN). Clamp to 0, mirroring the e > 8 clamp below. + e = 0; + } + + if (e > 8) { + if (precision > 0) { + precision += 8 - e; + } + return { e: 8, precision }; + } + + return { e, precision }; +} + +/** + * Applies rounding to the raw calculated value and handles auto-increment ceiling + * @param {number} val - Raw value before rounding + * @param {number} ceil - Ceiling threshold (1000 for SI, 1024 for IEC) + * @param {number} e - Current exponent value + * @param {number} round - Number of decimal places + * @param {Function} roundingFunc - Rounding method (Math.round, Math.floor, Math.ceil) + * @param {boolean} autoExponent - Whether exponent is auto-calculated (-1 or NaN) + * @returns {Object} Object with rounded value and possibly incremented exponent + */ +export function applyRounding(val, ceil, e, round, roundingFunc, autoExponent) { + let p; + if (e > 0 && round > 0) { + p = Math.pow(10, round); + } else { + p = 1; + } + let r; + if (p === 1) { + r = roundingFunc(val); + } else { + r = roundingFunc(val * p) / p; + } + + if (r === ceil && e < 8 && autoExponent) { + r = 1; + e++; + } + + return { value: r, e }; +} + +/** + * Resolves the unit symbol for the given standard, bits mode, and exponent + * Handles SI standard special case where exponent 1 always uses "kB" or "kbit" + * @param {string} actualStandard - The resolved standard (iec, jedec) + * @param {boolean} bits - Whether formatting bit values + * @param {number} e - Current exponent index + * @param {boolean} isDecimal - Whether using decimal (SI) base + * @returns {string} The resolved unit symbol string + */ +export function resolveSymbol(actualStandard, bits, e, isDecimal) { + const symbolTable = STRINGS.symbol[actualStandard][bits ? BITS : BYTES]; + let result; + if (isDecimal && e === 1) { + if (bits) { + result = SI_KBIT; + } else { + result = SI_KBYTE; + } + } else { + result = symbolTable[e]; + } + return result; +} + +/** + * Decorates the result: applies negation, custom symbols, number formatting, and full form names + * Mutates the result array in-place for both value (index 0) and symbol (index 1) + * @param {Array} result - Result array with numeric value at [0] and string symbol at [1] + * @param {boolean} neg - Whether the original input was negative + * @param {Object} symbols - Custom symbol override map + * @param {string|boolean} locale - Locale string for formatting + * @param {Object} localeOptions - Additional locale formatting options + * @param {string} separator - Custom decimal separator + * @param {boolean} pad - Whether zero-pad decimals + * @param {number} round - Target decimal count for padding + * @param {boolean} full - Whether to use full unit names + * @param {Array} fullforms - Custom full unit name overrides + * @param {string} actualStandard - Unit standard for full form lookup + * @param {number} e - Current exponent index + * @param {boolean} bits - Whether formatting bit values + * @returns {void} Mutates result array in place + */ +export function decorateResult( + result, + neg, + symbols, + locale, + localeOptions, + separator, + pad, + round, + full, + fullforms, + actualStandard, + e, + bits, + roundingFunc, +) { + if (neg) { + // `precision` leaves the value as a string from toPrecision (e.g. "1.50"). + // Negating that arithmetically coerces it back to a number and drops the + // trailing zeros the option asked for, so prefix the sign instead. + result[0] = typeof result[0] === "string" ? `-${result[0]}` : -result[0]; + } + + if (symbols[result[1]]) { + result[1] = symbols[result[1]]; + } + + // Capture the numeric value before formatting; a comma decimal separator + // (via separator or a locale such as de-DE) would otherwise make parseFloat + // read "1,5" as 1 and select the singular unit name. + let numericValue; + if (typeof result[0] === "string") { + numericValue = parseFloat(result[0]); + } else { + numericValue = result[0]; + } + + result[0] = applyNumberFormatting( + result[0], + locale, + localeOptions, + separator, + pad, + round, + roundingFunc, + ); + + if (full) { + let unit; + if (bits) { + unit = BIT; + } else { + unit = BYTE; + } + // Determine singular/plural suffix + let suffix; + if (numericValue === 1) { + suffix = EMPTY; + } else { + suffix = S; + } + // Determine symbol — custom fullforms are the complete name, defaults get unit+suffix + if (fullforms[e]) { + result[1] = fullforms[e]; + } else { + result[1] = STRINGS.fullform[actualStandard][e] + unit + suffix; + } + } +} + +/** + * Formats the computed result array into the requested output type + * @param {Array} result - Result array with formatted value at [0] and symbol at [1] + * @param {number} e - Current exponent + * @param {string} u - Original resolved symbol (before custom override) + * @param {string} output - Output type (ARRAY, OBJECT, STRING) + * @param {string} spacer - String separator between value and unit + * @returns {string|Array|Object|number} Formatted result in requested type + */ +export function formatOutput(result, e, u, output, spacer) { + if (output === ARRAY) { + return result; + } + + if (output === OBJECT) { + return { + value: result[0], + symbol: result[1], + exponent: e, + unit: u, + }; + } + + let formatted; + if (spacer === SPACE) { + formatted = `${result[0]} ${result[1]}`; + } else { + formatted = result.join(spacer); + } + return formatted; +} diff --git a/tests/unit/filesize.test.js b/tests/unit/filesize.test.js new file mode 100644 index 0000000..9434777 --- /dev/null +++ b/tests/unit/filesize.test.js @@ -0,0 +1,1098 @@ +/** + * Unit tests for filesize.js + * Tests the main filesize function and partial function + */ + +import assert from "node:assert"; +import { describe, it } from "node:test"; +import { filesize, partial } from "../../src/filesize.js"; + +describe("filesize", () => { + describe("Basic functionality", () => { + it("should convert bytes to human readable format", () => { + assert.strictEqual(filesize(1000), "1 kB"); + assert.strictEqual(filesize(1000000), "1 MB"); + assert.strictEqual(filesize(1000000000), "1 GB"); + }); + + it("should handle zero bytes", () => { + assert.strictEqual(filesize(0), "0 B"); + }); + + it("should handle small numbers", () => { + assert.strictEqual(filesize(1), "1 B"); + assert.strictEqual(filesize(512), "512 B"); + }); + + it("should handle negative numbers", () => { + assert.strictEqual(filesize(-1000), "-1 kB"); + assert.strictEqual(filesize(-1000000), "-1 MB"); + }); + + it("should throw TypeError for Infinity", () => { + assert.throws(() => filesize(Infinity), TypeError); + }); + + it("should throw TypeError for -Infinity", () => { + assert.throws(() => filesize(-Infinity), TypeError); + }); + }); + + describe("Bits option", () => { + it("should convert to bits when bits option is true", () => { + assert.strictEqual(filesize(1000, { bits: true }), "8 kbit"); + assert.strictEqual(filesize(1000000, { bits: true }), "8 Mbit"); + }); + + it("should handle zero with bits option", () => { + assert.strictEqual(filesize(0, { bits: true }), "0 bit"); + }); + + it("should respect forced exponent with bits", () => { + // Forced exponent should prevent auto-increment + assert.strictEqual(filesize(1024, { exponent: 0, bits: true }), "8192 bit"); + assert.strictEqual(filesize(1024, { exponent: 1, bits: true }), "8.19 kbit"); + }); + }); + + describe("Zero value edge cases", () => { + it("should handle zero with exponent output", () => { + assert.strictEqual(filesize(0, { output: "exponent" }), 0); + }); + + it("should pad zero like any other value", () => { + assert.strictEqual(filesize(0, { pad: true, round: 2 }), "0.00 B"); + assert.strictEqual(filesize(0, { pad: true, round: 3 }), "0.000 B"); + assert.strictEqual(filesize(0, { pad: true, round: 0 }), "0 B"); + }); + + it("should prefer precision over pad for zero", () => { + assert.strictEqual(filesize(0, { precision: 3, pad: true, round: 5 }), "0.00 B"); + }); + + it("should handle zero with custom symbols", () => { + assert.strictEqual(filesize(0, { symbols: { B: "Bytes" } }), "0 Bytes"); + }); + + it("should handle zero with fullform", () => { + assert.strictEqual(filesize(0, { fullform: true }), "0 byte"); + }); + + it("should handle zero with fullform and bits", () => { + assert.strictEqual(filesize(0, { fullform: true, bits: true }), "0 bit"); + }); + + it("should handle zero with array output", () => { + const result = filesize(0, { output: "array" }); + assert.deepStrictEqual(result, [0, "B"]); + }); + + it("should handle zero with object output", () => { + const result = filesize(0, { output: "object" }); + assert.deepStrictEqual(result, { value: 0, symbol: "B", exponent: 0, unit: "B" }); + }); + }); + + describe("Standards", () => { + it("should use IEC standard", () => { + assert.strictEqual(filesize(1024, { standard: "iec" }), "1 KiB"); + assert.strictEqual(filesize(1048576, { standard: "iec" }), "1 MiB"); + }); + + it("should use JEDEC standard", () => { + assert.strictEqual(filesize(1024, { standard: "jedec" }), "1 KB"); + assert.strictEqual(filesize(1048576, { standard: "jedec" }), "1 MB"); + }); + + it("should use SI standard", () => { + assert.strictEqual(filesize(1000, { standard: "si" }), "1 kB"); + assert.strictEqual(filesize(1000000, { standard: "si" }), "1 MB"); + }); + }); + + describe("Output formats", () => { + it("should return string by default", () => { + const result = filesize(1000); + assert.strictEqual(typeof result, "string"); + assert.strictEqual(result, "1 kB"); + }); + + it('should return array when output is "array"', () => { + const result = filesize(1000, { output: "array" }); + assert(Array.isArray(result)); + assert.strictEqual(result[0], 1); + assert.strictEqual(result[1], "kB"); + }); + + it('should return object when output is "object"', () => { + const result = filesize(1000, { output: "object" }); + assert.strictEqual(typeof result, "object"); + assert.strictEqual(result.value, 1); + assert.strictEqual(result.symbol, "kB"); + assert.strictEqual(result.exponent, 1); + assert.strictEqual(result.unit, "kB"); + }); + + it('should return exponent when output is "exponent"', () => { + const result = filesize(1000, { output: "exponent" }); + assert.strictEqual(typeof result, "number"); + assert.strictEqual(result, 1); + }); + + it("should match the object exponent when rounding overflows the unit", () => { + // 999999 renders as "1 MB", so the exponent is 2, not 1 + assert.strictEqual(filesize(999999, { output: "exponent" }), 2); + assert.strictEqual( + filesize(999999, { output: "exponent" }), + filesize(999999, { output: "object" }).exponent, + ); + // IEC: 1048575 renders as "1 MiB" + assert.strictEqual(filesize(1048575, { standard: "iec", output: "exponent" }), 2); + }); + + it("should match the object exponent when bits auto-increment the unit", () => { + // 125000 bytes = 1 Mbit, so the exponent is 2, not 1 + assert.strictEqual(filesize(125000, { bits: true, output: "exponent" }), 2); + assert.strictEqual( + filesize(125000, { bits: true, output: "exponent" }), + filesize(125000, { bits: true, output: "object" }).exponent, + ); + }); + }); + + describe("Rounding", () => { + it("should round to specified decimal places", () => { + assert.strictEqual(filesize(1536, { round: 1 }), "1.5 kB"); + assert.strictEqual(filesize(1536, { round: 0 }), "2 kB"); + assert.strictEqual(filesize(1536, { round: 3 }), "1.536 kB"); + }); + + it("should use different rounding methods", () => { + assert.strictEqual(filesize(1536, { roundingMethod: "floor" }), "1.53 kB"); + assert.strictEqual(filesize(1536, { roundingMethod: "ceil" }), "1.54 kB"); + assert.strictEqual(filesize(1536, { roundingMethod: "round" }), "1.54 kB"); + }); + }); + + describe("Padding", () => { + it("should pad decimal places when pad is true", () => { + assert.strictEqual(filesize(1000, { pad: true, round: 2 }), "1.00 kB"); + assert.strictEqual(filesize(1536, { pad: true, round: 1 }), "1.5 kB"); + }); + + it("should pad decimal places for negative numbers", () => { + assert.strictEqual(filesize(-1000, { pad: true, round: 2 }), "-1.00 kB"); + assert.strictEqual(filesize(-1536, { pad: true, round: 2 }), "-1.54 kB"); + assert.strictEqual(filesize(-1024, { pad: true, round: 3 }), "-1.024 kB"); + }); + + it("should pad decimal places with locale formatting for negative numbers", () => { + assert.strictEqual(filesize(-1536, { locale: "de", pad: true, round: 2 }), "-1,54 kB"); + assert.strictEqual(filesize(-1000, { locale: "en-US", pad: true, round: 2 }), "-1.00 kB"); + }); + + it("should pad decimal places with locale formatting and grouping separators", () => { + // German locale: comma as decimal separator, dot as grouping separator + // Verify comma is correctly detected as decimal separator (not grouping separator) + assert.strictEqual(filesize(1234567, { locale: "de-DE", pad: true, round: 2 }), "1,23 MB"); + // Padding with German locale (3 decimal places) + assert.strictEqual(filesize(1536, { locale: "de-DE", pad: true, round: 3 }), "1,536 kB"); + // German locale with padding that adds decimal places + assert.strictEqual(filesize(1536, { locale: "de", pad: true, round: 4 }), "1,5360 kB"); + // German locale with grouping separator in integer part (1.234.567,89 kB) + assert.strictEqual( + filesize(1234567890, { locale: "de", exponent: 1, pad: true, round: 2 }), + "1.234.567,89 kB", + ); + // English locale with larger numbers + assert.strictEqual(filesize(1234567, { locale: "en-US", pad: true, round: 2 }), "1.23 MB"); + assert.strictEqual(filesize(1234567890, { locale: "en-US", pad: true, round: 2 }), "1.23 GB"); + }); + + it("should keep every digit group and pad when an integer value has grouping separators", () => { + // en: comma grouping with no decimal in the raw value. Previously the + // trailing grouping comma was mistaken for the decimal separator, which + // dropped digit groups and skipped padding. + assert.strictEqual( + filesize(1234500e24, { locale: "en", pad: true, round: 2 }), + "1,234,500.00 YB", + ); + assert.strictEqual(filesize(1000e24, { locale: "en", pad: true, round: 2 }), "1,000.00 YB"); + }); + }); + + describe("Custom separators and spacers", () => { + it("should use custom decimal separator", () => { + assert.strictEqual(filesize(1536, { separator: "," }), "1,54 kB"); + }); + + it("should use custom spacer between value and unit", () => { + assert.strictEqual(filesize(1000, { spacer: "_" }), "1_kB"); + assert.strictEqual(filesize(1000, { spacer: "" }), "1kB"); + }); + }); + + describe("Custom symbols", () => { + it("should use custom symbols when provided", () => { + const customSymbols = { kB: "kilobyte" }; + assert.strictEqual(filesize(1000, { symbols: customSymbols }), "1 kilobyte"); + }); + }); + + describe("Locale formatting", () => { + it("should format using system locale when locale is true", () => { + const result = filesize(1000, { locale: true }); + assert(typeof result === "string"); + assert(result.includes("kB")); + }); + + it("should format using specific locale", () => { + const result = filesize(1536, { locale: "en-US" }); + assert(typeof result === "string"); + assert(result.includes("1.5")); + }); + }); + + describe("Full form names", () => { + it("should use full form names when fullform is true", () => { + assert.strictEqual(filesize(1000, { fullform: true }), "1 kilobyte"); + assert.strictEqual(filesize(2000, { fullform: true }), "2 kilobytes"); + assert.strictEqual(filesize(1, { fullform: true }), "1 byte"); + }); + + it("should use custom fullforms when provided", () => { + const customFullforms = ["", "thousand-byte"]; + assert.strictEqual( + filesize(1000, { fullform: true, fullforms: customFullforms }), + "1 thousand-byte", + ); + }); + + it("should handle bits fullform singular", () => { + assert.strictEqual(filesize(0.125, { bits: true, fullform: true }), "1 bit"); + }); + + it("should handle bits fullform plural", () => { + assert.strictEqual(filesize(0.25, { bits: true, fullform: true }), "2 bits"); + }); + + it("should handle fullform with precision (string value path)", () => { + assert.strictEqual( + filesize(1058223158, { standard: "iec", precision: 3, fullform: true }), + "0.990 gibibytes", + ); + assert.strictEqual(filesize(1234567890, { precision: 2, fullform: true }), "1.2 gigabytes"); + }); + + it("should keep the plural fullform when a comma decimal separator is used", () => { + assert.strictEqual(filesize(1500000, { fullform: true, separator: "," }), "1,5 megabytes"); + assert.strictEqual(filesize(1500000, { fullform: true, locale: "de-DE" }), "1,5 megabytes"); + }); + }); + + describe("Base and exponent options", () => { + it("should use base 2 calculations", () => { + assert.strictEqual(filesize(1024, { base: 2 }), "1 KiB"); + }); + + it("should use base 10 calculations", () => { + assert.strictEqual(filesize(1000, { base: 10 }), "1 kB"); + }); + + it("should use forced exponent", () => { + assert.strictEqual(filesize(1024, { exponent: 0 }), "1024 B"); + assert.strictEqual(filesize(1024, { exponent: 2 }), "0 MB"); + }); + }); + + describe("Precision option", () => { + it("should use specified precision", () => { + assert.strictEqual(filesize(1536, { precision: 3 }), "1.54 kB"); + assert.strictEqual(filesize(1536000, { precision: 2 }), "1.5 MB"); + }); + + it("should remove scientific notation from precision results", () => { + // Test cases where toPrecision would normally produce scientific notation + // but our implementation removes it by splitting on "e" + + // Very large numbers that would produce scientific notation + assert.strictEqual(filesize(1234567890123, { precision: 2 }), "1.2 TB"); + assert.strictEqual(filesize(9876543210987, { precision: 3 }), "9.88 TB"); + + // Test with different precision values on large numbers + assert.strictEqual(filesize(1e15, { precision: 1 }), "1 PB"); + assert.strictEqual(filesize(1e15, { precision: 2 }), "1.0 PB"); + assert.strictEqual(filesize(1e15, { precision: 3 }), "1.00 PB"); + }); + + it("should handle precision with very small numbers", () => { + // Very small numbers (less than 1 byte) + assert.strictEqual(filesize(0.001, { precision: 1 }), "0 B"); + assert.strictEqual(filesize(0.1, { precision: 2 }), "0.0 B"); + assert.strictEqual(filesize(0.5, { precision: 1 }), "1 B"); + }); + + it("should handle precision with numbers that would produce e+ notation", () => { + // Numbers that produce e+ notation with toPrecision + const largeNum = 1234567890; + assert.strictEqual(filesize(largeNum, { precision: 2 }), "1.2 GB"); + assert.strictEqual(filesize(largeNum, { precision: 3 }), "1.23 GB"); + assert.strictEqual(filesize(largeNum, { precision: 1 }), "1 GB"); + }); + + it("should handle precision with numbers that would produce e- notation", () => { + // Very small decimal numbers that would produce e- notation + assert.strictEqual(filesize(0.0001, { precision: 1 }), "0 B"); + assert.strictEqual(filesize(0.00001, { precision: 2 }), "0.0 B"); + }); + + it("should work with precision and different standards", () => { + const largeNum = 1234567890; + assert.strictEqual(filesize(largeNum, { precision: 2, standard: "iec" }), "1.1 GiB"); + assert.strictEqual(filesize(largeNum, { precision: 2, standard: "jedec" }), "1.1 GB"); + assert.strictEqual(filesize(largeNum, { precision: 2, standard: "si" }), "1.2 GB"); + }); + + it("should work with precision and bits option", () => { + const largeNum = 1234567890; + assert.strictEqual(filesize(largeNum, { precision: 2, bits: true }), "9.9 Gbit"); + assert.strictEqual(filesize(largeNum, { precision: 3, bits: true }), "9.88 Gbit"); + }); + + it("should work with precision and array output", () => { + const result = filesize(1234567890, { precision: 2, output: "array" }); + assert(Array.isArray(result)); + assert.strictEqual(result[0], "1.2"); + assert.strictEqual(result[1], "GB"); + }); + + it("should work with precision and object output", () => { + const result = filesize(1234567890, { precision: 2, output: "object" }); + assert.strictEqual(typeof result, "object"); + assert.strictEqual(result.value, "1.2"); + assert.strictEqual(result.symbol, "GB"); + }); + + it("should handle precision with extremely large numbers", () => { + // Test with numbers that exceed normal exponent range + const extremeNumber = Math.pow(1024, 15); + const result = filesize(extremeNumber, { precision: 2 }); + assert(typeof result === "string"); + // Note: For extremely large numbers that exceed JavaScript's normal number range, + // the number itself may be in scientific notation, which is expected behavior + assert(result.includes("YB") || result.includes("YiB")); + }); + + it("should handle precision edge cases", () => { + // Test precision with zero + assert.strictEqual(filesize(0, { precision: 3 }), "0.00 B"); + + // Test precision with exactly 1 byte + assert.strictEqual(filesize(1, { precision: 2 }), "1.0 B"); + + // Test precision with negative numbers + assert.strictEqual(filesize(-1234567890, { precision: 2 }), "-1.2 GB"); + }); + + it("should keep precision trailing zeros for negative values", () => { + // A negative value must carry the same significant digits as its positive counterpart + assert.strictEqual(filesize(1500, { precision: 3 }), "1.50 kB"); + assert.strictEqual(filesize(-1500, { precision: 3 }), "-1.50 kB"); + assert.strictEqual(filesize(-1000, { precision: 3 }), "-1.00 kB"); + assert.strictEqual(filesize(-1, { precision: 3 }), "-1.00 B"); + assert.deepStrictEqual(filesize(-1500, { precision: 3, output: "array" }), ["-1.50", "kB"]); + assert.strictEqual(filesize(-1500, { precision: 3, output: "object" }).value, "-1.50"); + }); + + it("should ensure no scientific notation in any precision result", () => { + // Test a range of numbers that would normally produce scientific notation from toPrecision + // but should have it removed by our implementation + const testNumbers = [1e3, 1e6, 1e9, 1e12, 1234567890123456, Math.pow(10, 10)]; + + testNumbers.forEach((num) => { + [1, 2, 3, 4].forEach((precision) => { + const result = filesize(num, { precision }); + // Result should not contain scientific notation markers when using toPrecision + // Note: We exclude extremely large numbers that naturally contain 'e' in JavaScript + if (!num.toString().includes("e")) { + assert( + !result.includes("e"), + `Result "${result}" contains 'e' for number ${num} with precision ${precision}`, + ); + assert( + !result.includes("E"), + `Result "${result}" contains 'E' for number ${num} with precision ${precision}`, + ); + } + }); + }); + }); + + it("should handle precision with base 2 when scientific notation is produced (regular number)", () => { + // Test case that triggers base === 2 path in line 168 precision handling + // We need a number that will produce scientific notation with toPrecision + // and uses base 2 (IEC standard) + const testNumber = 999999999999999; // Large number that triggers scientific notation + const result = filesize(testNumber, { precision: 1, standard: "iec" }); + assert(typeof result === "string"); + assert(!result.includes("e")); + assert(!result.includes("E")); + // Should use IEC units (base 2) + assert(result.includes("TiB") || result.includes("PiB")); + }); + + it("should handle precision with base 2 when scientific notation is produced (BigInt)", () => { + // Test case that triggers base === 2 path in line 168 precision handling using BigInt + // This ensures both number types are tested for base 2 path + const testNumber = BigInt("999999999999999"); // Large BigInt that triggers scientific notation + const result = filesize(testNumber, { precision: 1, standard: "iec" }); + assert(typeof result === "string"); + assert(!result.includes("e")); + assert(!result.includes("E")); + // Should use IEC units (base 2) + assert(result.includes("TiB") || result.includes("PiB")); + }); + + it("should handle precision with base 10 when scientific notation is produced (regular number)", () => { + // Test case that triggers base === 10 path in line 168 precision handling + // We need a number that will produce scientific notation with toPrecision + // and uses base 10 (SI/JEDEC standard) + const testNumber = 999999999999999; // Large number that triggers scientific notation + const result = filesize(testNumber, { precision: 1, standard: "jedec" }); + assert(typeof result === "string"); + assert(!result.includes("e")); + assert(!result.includes("E")); + // Should use JEDEC units (base 10 logic) + assert(result.includes("TB") || result.includes("PB")); + }); + + it("should handle precision with base 10 when scientific notation is produced (BigInt)", () => { + // Test case that triggers base === 10 path in line 168 precision handling using BigInt + // This ensures both number types are tested for base 10 path + const testNumber = BigInt("999999999999999"); // Large BigInt that triggers scientific notation + const result = filesize(testNumber, { precision: 1, standard: "jedec" }); + assert(typeof result === "string"); + assert(!result.includes("e")); + assert(!result.includes("E")); + // Should use JEDEC units (base 10 logic) + assert(result.includes("TB") || result.includes("PB")); + }); + + it("should handle precision with YiB-level numbers where e >= 8 (regular number)", () => { + // Test case that covers line 166 when e >= 8 (YiB level) using regular number + // This triggers result[0].includes(E) but e < 8 is false, so increment logic is skipped + const yibNumber = Math.pow(1024, 8); // 1 YiB in bytes using regular number + const result = filesize(yibNumber, { precision: 1, standard: "iec" }); + assert(typeof result === "string"); + // For extremely large regular numbers, some scientific notation may be expected + assert(result.includes("YiB")); + }); + + it("should handle precision with YiB-level numbers where e >= 8 (BigInt)", () => { + // Test case that covers line 166 when e >= 8 (YiB level) using BigInt + // This triggers result[0].includes(E) but e < 8 is false, so increment logic is skipped + // YiB is at exponent 8, so we need a number large enough to reach this level + const yibNumber = BigInt(1024) ** BigInt(8); // 1 YiB in bytes using BigInt + const result = filesize(yibNumber, { precision: 1, standard: "iec" }); + assert(typeof result === "string"); + assert(!result.includes("e")); + assert(!result.includes("E")); + assert(result.includes("YiB")); + }); + + it("should handle precision with extremely large numbers that exceed YiB (regular number)", () => { + // Test case for numbers that are larger than YiB using regular number + // This ensures we test the e >= 8 condition thoroughly with regular numbers + const extremeNumber = Math.pow(1024, 8) * 1000; // 1000 YiB using regular number + const result = filesize(extremeNumber, { precision: 2, standard: "iec" }); + assert(typeof result === "string"); + // For extremely large regular numbers, some scientific notation may be expected + assert(result.includes("YiB")); + }); + + it("should handle precision with extremely large numbers that exceed YiB (BigInt)", () => { + // Test case for numbers that are larger than YiB using BigInt + // This ensures we test the e >= 8 condition thoroughly with BigInt + const extremeNumber = BigInt(1024) ** BigInt(8) * BigInt(1000); // 1000 YiB using BigInt + const result = filesize(extremeNumber, { precision: 2, standard: "iec" }); + assert(typeof result === "string"); + // For extremely large BigInt numbers, the result should still use YiB units + // Some scientific notation in the final result may be acceptable for such large numbers + assert(result.includes("YiB")); + }); + + it("should handle precision with specific test case for GiB values", () => { + // Test specific precision case: filesize(1058223158, {base: 2, standard: 'iec', precision: 3}) + // This should output '0.990 GiB' + assert.strictEqual( + filesize(1058223158, { base: 2, standard: "iec", precision: 3 }), + "0.990 GiB", + ); + }); + + it("should return string value in object output when precision > 0", () => { + const result = filesize(1234567890, { precision: 2, output: "object" }); + assert.strictEqual(typeof result.value, "string"); + assert.strictEqual(result.value, "1.2"); + }); + + it("should skip padding when round is 0", () => { + assert.strictEqual(filesize(1000, { pad: true, round: 0 }), "1 kB"); + }); + + it("should fall back to JEDEC default for unknown standard", () => { + assert.strictEqual(filesize(1024, { standard: "foobar" }), "1.02 kB"); + }); + }); + + describe("Edge cases", () => { + it("should handle very large numbers", () => { + const largeNumber = Math.pow(1024, 8); + const result = filesize(largeNumber); + assert(typeof result === "string"); + assert(result.includes("YB") || result.includes("YiB")); + }); + + it("should handle BigInt input", () => { + const result = filesize(BigInt(1024), { standard: "jedec" }); + assert.strictEqual(result, "1 KB"); + }); + + it("should handle numbers exceeding maximum exponent", () => { + const hugeNumber = Math.pow(1024, 10); + const result = filesize(hugeNumber); + assert(typeof result === "string"); + }); + + it("should handle numbers exceeding lookup table size (decimal)", () => { + // Test number requiring Math.pow fallback for decimal powers + const hugeNumber = Math.pow(1000, 15); // Exceeds DECIMAL_POWERS array + const result = filesize(hugeNumber, { base: 10 }); + assert.ok(result.includes("YB")); + }); + + it("should handle numbers exceeding lookup table size (binary)", () => { + // Test number requiring Math.pow fallback for binary powers + const hugeNumber = Math.pow(2, 100); // Exceeds BINARY_POWERS array + const result = filesize(hugeNumber, { base: 2 }); + assert.ok(result.includes("YiB")); + }); + + it("should handle precision with numbers exceeding lookup table", () => { + const hugeNumber = Math.pow(1000, 12); + const result = filesize(hugeNumber, { precision: 2, base: 10 }); + assert.ok(result.includes("YB")); + }); + + it("should handle precision with round=0 and scientific notation", () => { + // Test case where p === 1 in the precision recalculation branch + const result = filesize(1000000000000000000, { precision: 1, round: 0 }); + assert.ok(typeof result === "string"); + }); + + it("should cover p===1 branch in precision recalculation", () => { + // Try to force the p===1 branch in the precision recalculation + // This needs a very specific edge case where scientific notation is produced + // and after increment e=0 or round=0 makes p=1 + const result = filesize(0.0001, { precision: 20, round: 0 }); + assert.ok(typeof result === "string"); + }); + + it("should trigger precision recalculation with bytes and round=0", () => { + // Another attempt: very small number that might produce scientific notation in bytes + const result = filesize(0.000000000000001, { precision: 30, round: 0 }); + assert.ok(typeof result === "string"); + }); + + it("should cover p===1 branch with input=1 and extreme precision", () => { + // When input=1, e=0, so p=1. High precision might trigger scientific notation + // and the recalculation with p===1 branch + const result = filesize(1, { precision: 50 }); + assert.ok(typeof result === "string"); + }); + + it("should attempt to trigger the elusive p===1 branch in recalculation", () => { + // Numbers that would produce scientific notation with precision=1 + // When e=0 (bytes), p=1, and toPrecision(1) might produce "1e+1" etc. + const result = filesize(10, { precision: 1, round: 0 }); + assert.ok(typeof result === "string"); + }); + + it("should handle extremely large numbers with precision adjustment", () => { + const extremeNumber = Math.pow(1024, 15); // Much larger than supported exponent + const result = filesize(extremeNumber, { precision: 3 }); + assert(typeof result === "string"); + assert(result.includes("YB") || result.includes("YiB")); + }); + + it("should handle bit conversion auto-increment near boundary", () => { + // Test edge case where bits conversion causes auto-increment to next unit + const result = filesize(127.5, { bits: true }); // Should auto-increment + assert(typeof result === "string"); + }); + + it("should handle result equal to ceil boundary for auto-increment", () => { + // Test case where result equals ceil and triggers increment + const result = filesize(999.5, { round: 0 }); // Should round to 1000 and increment + assert(typeof result === "string"); + }); + + it("should handle padding with custom separator edge cases", () => { + // Test padding when separator is found via regex + const result = filesize(1536, { pad: true, round: 2, locale: "de-DE" }); + assert(typeof result === "string"); + }); + + it("should handle NaN exponent edge case", () => { + const result = filesize(1000, { exponent: NaN }); + assert.strictEqual(result, "1 kB"); + }); + + it("should handle NaN exponent with precision", () => { + // NaN exponent should behave like auto (-1) and allow scientific notation normalization + const result = filesize(1e15, { exponent: NaN, precision: 2 }); + assert(typeof result === "string"); + assert(!result.includes("e"), "Should not contain scientific notation"); + }); + + it("should handle NaN exponent with auto-increment", () => { + // NaN exponent should allow auto-increment when result equals ceil (1024) + const result = filesize(1024, { exponent: NaN, standard: "iec" }); + assert.strictEqual(result, "1 KiB"); + }); + + it("should clamp an out-of-range negative exponent to 0 instead of returning NaN", () => { + // Only -1 is the documented "auto" sentinel. Any other negative exponent + // indexed the power lookup tables out of bounds and produced "NaN undefined". + assert.strictEqual(filesize(1024, { exponent: -2 }), "1024 B"); + assert.strictEqual(filesize(1024, { exponent: -100 }), "1024 B"); + }); + + it("should clamp a negative exponent to 0 for object output", () => { + const result = filesize(1024, { exponent: -3, output: "object" }); + assert.deepStrictEqual(result, { value: 1024, symbol: "B", exponent: 0, unit: "B" }); + }); + + it("should clamp a negative exponent to 0 for array output", () => { + const result = filesize(1024, { exponent: -3, output: "array" }); + assert.deepStrictEqual(result, [1024, "B"]); + }); + }); + + describe("Error handling", () => { + it("should throw TypeError for invalid number input", () => { + assert.throws(() => filesize("invalid"), TypeError); + assert.throws(() => filesize(NaN), TypeError); + assert.throws(() => filesize({}), TypeError); + }); + + it("should throw TypeError for invalid rounding method", () => { + assert.throws(() => filesize(1024, { roundingMethod: "invalid" }), TypeError); + assert.throws(() => filesize(1024, { roundingMethod: "nonexistent" }), TypeError); + }); + }); + + describe("Input type handling", () => { + describe("Number input", () => { + describe("filesize() with number input", () => { + it("should handle integer numbers", () => { + assert.strictEqual(filesize(1024), "1.02 kB"); + assert.strictEqual(filesize(0), "0 B"); + assert.strictEqual(filesize(-1024), "-1.02 kB"); + }); + + it("should handle floating point numbers", () => { + assert.strictEqual(filesize(1536.5), "1.54 kB"); + assert.strictEqual(filesize(0.5), "1 B"); + }); + + it("should handle very large numbers", () => { + const largeNumber = Number.MAX_SAFE_INTEGER; + const result = filesize(largeNumber); + assert(typeof result === "string"); + }); + }); + + describe("partial() with number input", () => { + it("should handle integer numbers", () => { + const formatIEC = partial({ standard: "iec" }); + assert.strictEqual(formatIEC(1024), "1 KiB"); + assert.strictEqual(formatIEC(0), "0 B"); + assert.strictEqual(formatIEC(-1024), "-1 KiB"); + }); + + it("should handle floating point numbers", () => { + const formatRounded = partial({ round: 1 }); + assert.strictEqual(formatRounded(1536.7), "1.5 kB"); + assert.strictEqual(formatRounded(0.5), "1 B"); + }); + + it("should handle very large numbers", () => { + const formatBits = partial({ bits: true }); + const largeNumber = Number.MAX_SAFE_INTEGER; + const result = formatBits(largeNumber); + assert(typeof result === "string"); + }); + }); + }); + + describe("String input", () => { + describe("filesize() with string input", () => { + it("should handle valid integer string", () => { + assert.strictEqual(filesize("1024"), "1.02 kB"); + assert.strictEqual(filesize("0"), "0 B"); + assert.strictEqual(filesize("-1024"), "-1.02 kB"); + }); + + it("should handle valid float string", () => { + assert.strictEqual(filesize("1536.5"), "1.54 kB"); + assert.strictEqual(filesize("0.5"), "1 B"); + }); + + it("should handle scientific notation string", () => { + assert.strictEqual(filesize("1e3"), "1 kB"); + assert.strictEqual(filesize("1.024e3"), "1.02 kB"); + }); + + it("should handle string with leading/trailing whitespace", () => { + assert.strictEqual(filesize(" 1024 "), "1.02 kB"); + assert.strictEqual(filesize("\t1024\n"), "1.02 kB"); + }); + + it("should work with string input and different options", () => { + assert.strictEqual(filesize("1024", { standard: "iec" }), "1 KiB"); + assert.strictEqual(filesize("1000", { bits: true }), "8 kbit"); + assert.strictEqual(filesize("1024", { output: "array" })[0], 1.02); + }); + }); + + describe("partial() with string input", () => { + it("should handle valid integer string", () => { + const formatJEDEC = partial({ standard: "jedec" }); + assert.strictEqual(formatJEDEC("1024"), "1 KB"); + assert.strictEqual(formatJEDEC("0"), "0 B"); + assert.strictEqual(formatJEDEC("-1024"), "-1 KB"); + }); + + it("should handle valid float string", () => { + const formatPadded = partial({ pad: true, round: 2 }); + assert.strictEqual(formatPadded("1536.5"), "1.54 kB"); + assert.strictEqual(formatPadded("0.5"), "1.00 B"); + }); + + it("should handle scientific notation string", () => { + const formatBits = partial({ bits: true }); + assert.strictEqual(formatBits("1e3"), "8 kbit"); + assert.strictEqual(formatBits("1.024e3"), "8.19 kbit"); + }); + + it("should handle string with leading/trailing whitespace", () => { + const formatFullForm = partial({ fullform: true, standard: "iec" }); + assert.strictEqual(formatFullForm(" 1024 "), "1 kibibyte"); + assert.strictEqual(formatFullForm("\t2048\n"), "2 kibibytes"); + }); + + it("should work with string input and complex options", () => { + const formatComplex = partial({ + standard: "si", + round: 1, + spacer: "_", + output: "array", + }); + const result = formatComplex("1000"); + assert(Array.isArray(result)); + assert.strictEqual(result[0], 1); + assert.strictEqual(result[1], "kB"); + }); + }); + }); + + describe("BigInt input", () => { + describe("filesize() with BigInt input", () => { + it("should handle regular BigInt values", () => { + assert.strictEqual(filesize(BigInt(1024)), "1.02 kB"); + assert.strictEqual(filesize(BigInt(0)), "0 B"); + assert.strictEqual(filesize(BigInt(-1024)), "-1.02 kB"); + }); + + it("should handle large BigInt values", () => { + const largeBigInt = BigInt("9007199254740992"); // 2^53 + const result = filesize(largeBigInt); + assert(typeof result === "string"); + assert(result.includes("PB") || result.includes("PiB")); + }); + + it("should handle very large BigInt values", () => { + const veryLargeBigInt = BigInt("1208925819614629174706176"); // 1024^8 + const result = filesize(veryLargeBigInt); + assert(typeof result === "string"); + assert(result.includes("YB") || result.includes("YiB")); + }); + + it("should work with BigInt input and different options", () => { + assert.strictEqual(filesize(BigInt(1024), { standard: "jedec" }), "1 KB"); + assert.strictEqual(filesize(BigInt(1000), { bits: true }), "8 kbit"); + + const objectResult = filesize(BigInt(1024), { output: "object" }); + assert.strictEqual(objectResult.value, 1.02); + assert.strictEqual(objectResult.symbol, "kB"); + }); + }); + + describe("partial() with BigInt input", () => { + it("should handle regular BigInt values", () => { + const formatCustomSymbols = partial({ symbols: { KiB: "kibibyte" }, standard: "iec" }); + assert.strictEqual(formatCustomSymbols(BigInt(1024)), "1 kibibyte"); + assert.strictEqual(formatCustomSymbols(BigInt(0)), "0 B"); + assert.strictEqual(formatCustomSymbols(BigInt(-1024)), "-1 kibibyte"); + }); + + it("should handle large BigInt values", () => { + const formatPrecision = partial({ precision: 3 }); + const largeBigInt = BigInt("9007199254740992"); // 2^53 + const result = formatPrecision(largeBigInt); + assert(typeof result === "string"); + assert(result.includes("PB") || result.includes("PiB")); + }); + + it("should handle very large BigInt values", () => { + const formatExponent = partial({ exponent: -1 }); // Auto-select exponent + const veryLargeBigInt = BigInt("1208925819614629174706176"); // 1024^8 + const result = formatExponent(veryLargeBigInt); + assert(typeof result === "string"); + assert(result.includes("YB") || result.includes("YiB")); + }); + + it("should work with BigInt input and different output formats", () => { + const formatObject = partial({ output: "object", standard: "iec" }); + const objectResult = formatObject(BigInt(1024)); + assert.strictEqual(typeof objectResult, "object"); + assert.strictEqual(objectResult.value, 1); + assert.strictEqual(objectResult.symbol, "KiB"); + + const formatExponentOnly = partial({ output: "exponent" }); + const exponentResult = formatExponentOnly(BigInt(1024)); + assert.strictEqual(typeof exponentResult, "number"); + assert.strictEqual(exponentResult, 1); + }); + + it("should work with BigInt input and bits option", () => { + const formatBits = partial({ bits: true, round: 1 }); + assert.strictEqual(formatBits(BigInt(1024)), "8.2 kbit"); + assert.strictEqual(formatBits(BigInt(1000)), "8 kbit"); + }); + + it("should work with BigInt input and locale formatting", () => { + const formatLocale = partial({ locale: "en-US", round: 2 }); + const result = formatLocale(BigInt(1536)); + assert(typeof result === "string"); + assert(result.includes("1.5") || result.includes("1.54")); + }); + }); + }); + }); +}); + +describe("partial", () => { + describe("Basic functionality", () => { + it("should create a function with preset options", () => { + const formatKiB = partial({ standard: "iec" }); + assert.strictEqual(typeof formatKiB, "function"); + assert.strictEqual(formatKiB(1024), "1 KiB"); + }); + + it("should preserve all options in partial application", () => { + const formatWithOptions = partial({ + round: 1, + standard: "iec", + spacer: "_", + }); + assert.strictEqual(formatWithOptions(1536), "1.5_KiB"); + }); + }); + + describe("Options inheritance", () => { + it("should apply bits option from partial", () => { + const formatBits = partial({ bits: true }); + assert.strictEqual(formatBits(1000), "8 kbit"); + }); + + it("should apply pad option from partial", () => { + const formatPadded = partial({ pad: true, round: 2 }); + assert.strictEqual(formatPadded(1000), "1.00 kB"); + }); + + it("should apply output format from partial", () => { + const formatArray = partial({ output: "array" }); + const result = formatArray(1000); + assert(Array.isArray(result)); + assert.strictEqual(result[0], 1); + assert.strictEqual(result[1], "kB"); + }); + + it("should apply custom symbols from partial", () => { + const formatCustom = partial({ symbols: { kB: "kilobyte" } }); + assert.strictEqual(formatCustom(1000), "1 kilobyte"); + }); + }); + + describe("Multiple partial functions", () => { + it("should create independent partial functions", () => { + const formatIEC = partial({ standard: "iec" }); + const formatJEDEC = partial({ standard: "jedec" }); + + assert.strictEqual(formatIEC(1024), "1 KiB"); + assert.strictEqual(formatJEDEC(1024), "1 KB"); + }); + + it("should handle complex option combinations", () => { + const formatComplex = partial({ + bits: true, + standard: "iec", + round: 1, + fullform: true, + }); + assert.strictEqual(formatComplex(1024), "8 kibibits"); + }); + }); + + describe("Precision with partial", () => { + it("should apply precision option from partial", () => { + const formatPrecision = partial({ precision: 2 }); + assert.strictEqual(formatPrecision(1234567890), "1.2 GB"); + assert.strictEqual(formatPrecision(9876543210), "9.9 GB"); + }); + + it("should remove scientific notation in partial functions", () => { + const formatWithPrecision = partial({ precision: 3 }); + const largeNum = 1234567890123; + const result = formatWithPrecision(largeNum); + assert(!result.includes("e")); + assert(!result.includes("E")); + assert.strictEqual(result, "1.23 TB"); + }); + + it("should work with precision and other options combined", () => { + const formatComplex = partial({ + precision: 2, + standard: "iec", + bits: true, + }); + const result = formatComplex(1234567890); + assert(!result.includes("e")); + assert(!result.includes("E")); + assert.strictEqual(result, "9.2 Gibit"); + }); + }); + + describe("Default behavior", () => { + it("should work with no options provided", () => { + const defaultFormat = partial(); + assert.strictEqual(typeof defaultFormat, "function"); + assert.strictEqual(defaultFormat(1000), "1 kB"); + }); + + it("should work with empty options object", () => { + const emptyOptions = partial({}); + assert.strictEqual(emptyOptions(1000), "1 kB"); + }); + }); + + describe("Immutability", () => { + it("should not be affected by mutations to top-level primitive options", () => { + const opts = { standard: "iec", round: 1 }; + const format = partial(opts); + + // First call should work normally + assert.strictEqual(format(1536), "1.5 KiB"); + + // Mutate the original options object + opts.standard = "jedec"; + opts.round = 0; + + // The partial function should still use the destructured primitive values + assert.strictEqual(format(1536), "1.5 KiB"); + }); + + it("should not affect other partial functions when modifying one", () => { + const format1 = partial({ symbols: { kB: "first_kB" } }); + const format2 = partial({ symbols: { kB: "second_kB" } }); + + // Both should work independently + assert.strictEqual(format1(1000), "1 first_kB"); + assert.strictEqual(format2(1000), "1 second_kB"); + }); + + it("should not be affected by mutations to localeOptions reference", () => { + const opts = { localeOptions: { useGrouping: true } }; + const format = partial(opts); + + assert.strictEqual(typeof format(1234567), "string"); + + opts.localeOptions.useGrouping = false; + assert.strictEqual(typeof format(1234567), "string"); + }); + + it("should not be affected by mutations to symbols reference", () => { + const opts = { symbols: { kB: "original_kB" } }; + const format = partial(opts); + + assert.strictEqual(format(1000), "1 original_kB"); + + opts.symbols.kB = "mutated_kB"; + assert.strictEqual(format(1000), "1 original_kB"); + }); + + it("should not be affected by mutations to fullforms reference", () => { + const opts = { fullforms: ["custom"], fullform: true }; + const format = partial(opts); + + assert.strictEqual(format(1), "1 custom"); + + opts.fullforms[0] = "mutated"; + assert.strictEqual(format(1), "1 custom"); + }); + }); +}); + +describe("partial structuredClone", () => { + it("should use structuredClone when available for localeOptions", () => { + const opts = { localeOptions: { minimumFractionDigits: 2 } }; + const format = partial(opts); + const result = format(1234.5); + assert(typeof result === "string"); + // Mutate original - should not affect partial + opts.localeOptions.minimumFractionDigits = 5; + const result2 = format(1234.5); + assert(typeof result2 === "string"); + }); + + it("should use structuredClone when available for symbols", () => { + const opts = { symbols: { kB: "custom_kB" } }; + const format = partial(opts); + assert.strictEqual(format(1000), "1 custom_kB"); + opts.symbols.kB = "mutated_kB"; + assert.strictEqual(format(1000), "1 custom_kB"); + }); + + it("should use structuredClone when available for fullforms", () => { + const opts = { fullforms: ["my_byte"], fullform: true }; + const format = partial(opts); + assert.strictEqual(format(1), "1 my_byte"); + opts.fullforms[0] = "mutated"; + assert.strictEqual(format(1), "1 my_byte"); + }); + + it("should maintain deep independence between partial instances", () => { + const opts1 = { symbols: { kB: "first" } }; + const opts2 = { symbols: { kB: "second" } }; + const format1 = partial(opts1); + const format2 = partial(opts2); + assert.strictEqual(format1(1000), "1 first"); + assert.strictEqual(format2(1000), "1 second"); + opts1.symbols.kB = "mutated_first"; + opts2.symbols.kB = "mutated_second"; + assert.strictEqual(format1(1000), "1 first"); + assert.strictEqual(format2(1000), "1 second"); + }); +});