├── .npmrc ├── src ├── errors.ts ├── locales │ ├── index.ts │ ├── zh.ts │ ├── ja.ts │ ├── hi.ts │ ├── en.ts │ ├── fr.ts │ ├── es.ts │ └── de.ts ├── index.ts ├── index.test.ts ├── index.bench.ts ├── unformatter.test.ts ├── typings.ts ├── cldr-utils.ts ├── unformatter.ts ├── utils.ts ├── store.ts ├── formatter.ts ├── utils.test.ts └── formatter.test.ts ├── tsup.config.ts ├── .prettierignore ├── tsconfig.json ├── vitest.config.ts ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── release.yml ├── eslint.config.mjs ├── LICENSE ├── package.json ├── .gitignore ├── scripts └── generate-locales.ts ├── README.md └── pnpm-lock.yaml /.npmrc: -------------------------------------------------------------------------------- 1 | hoist=true 2 | shamefully-hoist=true 3 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | export class CompactNumberError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = 'CompactNumberError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/locales/index.ts: -------------------------------------------------------------------------------- 1 | export * from './en'; 2 | export * from './de'; 3 | export * from './es'; 4 | export * from './fr'; 5 | export * from './hi'; 6 | export * from './ja'; 7 | export * from './zh'; 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { compactNumber } from './formatter'; 2 | export { uncompactNumber } from './unformatter'; 3 | export { store } from './store'; 4 | export * from './locales'; 5 | export type * from './typings'; 6 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig({ 4 | clean: true, 5 | dts: true, 6 | entry: ['src/index.ts'], 7 | format: ['cjs', 'esm'], 8 | target: 'esnext', 9 | outDir: 'dist', 10 | }); 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .changeset 3 | node_modules 4 | build 5 | dist 6 | 7 | .gitignore 8 | .prettierignore 9 | 10 | .env 11 | .env.* 12 | !.env.example 13 | 14 | # Ignore files for PNPM, NPM and YARN 15 | package-lock.json 16 | yarn.lock 17 | pnpm-lock.yaml 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@shahrad/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | }, 10 | "include": ["**/*.ts"], 11 | "exclude": ["node_modules", "dist"] 12 | } 13 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | environment: 'node', 6 | testTimeout: 20000, 7 | globals: true, 8 | exclude: ['**/node_modules/**', '**/dist/**'], 9 | }, 10 | resolve: { 11 | alias: { 12 | '@': '/src', 13 | }, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | groups: 8 | all-dependencies: 9 | patterns: 10 | - '*' 11 | update-types: 12 | - 'minor' 13 | - 'patch' 14 | - package-ecosystem: 'github-actions' 15 | directory: '/' 16 | schedule: 17 | interval: 'daily' 18 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@shahrad/eslint-config'; 2 | import globals from 'globals'; 3 | 4 | export default defineConfig( 5 | { 6 | ignores: ['dist/**', 'scripts/**'], 7 | }, 8 | 9 | { 10 | languageOptions: { 11 | ecmaVersion: 'latest', 12 | sourceType: 'module', 13 | globals: { 14 | ...globals.node, 15 | ...globals.browser, 16 | }, 17 | }, 18 | rules: { 19 | 'no-console': 'error', 20 | }, 21 | } 22 | ); 23 | -------------------------------------------------------------------------------- /src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | 3 | import * as Exports from './index'; 4 | 5 | describe('index exports', () => { 6 | test('should export compactNumber, uncompactNumber, and store', () => { 7 | expect(Exports.compactNumber).toBeDefined(); 8 | expect(Exports.uncompactNumber).toBeDefined(); 9 | expect(Exports.store).toBeDefined(); 10 | }); 11 | 12 | test('should export locales', () => { 13 | expect(Exports.en).toBeDefined(); 14 | expect(Exports.de).toBeDefined(); 15 | expect(Exports.es).toBeDefined(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/index.bench.ts: -------------------------------------------------------------------------------- 1 | import { bench, describe } from 'vitest'; 2 | 3 | import { compactNumber } from './index'; 4 | 5 | describe('compactNumber vs. Intl.NumberFormat', () => { 6 | const numbers = [123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890]; 7 | 8 | bench('@se-oss/compact-number', () => { 9 | for (const number of numbers) { 10 | compactNumber(number, { 11 | style: 'short', 12 | minimumFractionDigits: 1, 13 | maximumFractionDigits: 1, 14 | }); 15 | } 16 | }); 17 | 18 | bench('Intl.NumberFormat', () => { 19 | const formatter = new Intl.NumberFormat('en', { 20 | notation: 'compact', 21 | compactDisplay: 'short', 22 | maximumFractionDigits: 1, 23 | minimumFractionDigits: 1, 24 | }); 25 | for (const number of numbers) { 26 | formatter.format(number); 27 | } 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/locales/zh.ts: -------------------------------------------------------------------------------- 1 | import type { FormatRules, LocaleData } from '@/typings'; 2 | 3 | const decimalValues: FormatRules = [ 4 | [1000, { one: ['', 0], other: ['0', 1] }], 5 | [10000, { one: ['', 0], other: ['0万', 1] }], 6 | [100000, { one: ['', 0], other: ['00万', 2] }], 7 | [1000000, { one: ['', 0], other: ['000万', 3] }], 8 | [10000000, { one: ['', 0], other: ['0000万', 4] }], 9 | [100000000, { one: ['', 0], other: ['0亿', 1] }], 10 | [1000000000, { one: ['', 0], other: ['00亿', 2] }], 11 | [10000000000, { one: ['', 0], other: ['000亿', 3] }], 12 | [100000000000, { one: ['', 0], other: ['0000亿', 4] }], 13 | [1000000000000, { one: ['', 0], other: ['0万亿', 1] }], 14 | [10000000000000, { one: ['', 0], other: ['00万亿', 2] }], 15 | [100000000000000, { one: ['', 0], other: ['000万亿', 3] }], 16 | ]; 17 | 18 | export const zh: LocaleData = { 19 | zh: { 20 | locale: 'zh', 21 | numbers: { 22 | decimal: { 23 | short: decimalValues, 24 | long: decimalValues, 25 | }, 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/locales/ja.ts: -------------------------------------------------------------------------------- 1 | import type { FormatRules, LocaleData } from '@/typings'; 2 | 3 | const decimalValues: FormatRules = [ 4 | [1000, { one: ['', 0], other: ['0', 1] }], 5 | [10000, { one: ['', 0], other: ['0万', 1] }], 6 | [100000, { one: ['', 0], other: ['00万', 2] }], 7 | [1000000, { one: ['', 0], other: ['000万', 3] }], 8 | [10000000, { one: ['', 0], other: ['0000万', 4] }], 9 | [100000000, { one: ['', 0], other: ['0億', 1] }], 10 | [1000000000, { one: ['', 0], other: ['00億', 2] }], 11 | [10000000000, { one: ['', 0], other: ['000億', 3] }], 12 | [100000000000, { one: ['', 0], other: ['0000億', 4] }], 13 | [1000000000000, { one: ['', 0], other: ['0兆', 1] }], 14 | [10000000000000, { one: ['', 0], other: ['00兆', 2] }], 15 | [100000000000000, { one: ['', 0], other: ['000兆', 3] }], 16 | [1000000000000000, { one: ['', 0], other: ['0000兆', 4] }], 17 | ]; 18 | 19 | export const ja: LocaleData = { 20 | ja: { 21 | locale: 'ja', 22 | numbers: { 23 | decimal: { 24 | short: decimalValues, 25 | long: decimalValues, 26 | }, 27 | }, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Shahrad Elahi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | 8 | jobs: 9 | format: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: pnpm/action-setup@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 22 17 | cache: 'pnpm' 18 | 19 | - run: pnpm install --frozen-lockfile 20 | - run: pnpm format:check 21 | 22 | lint: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: pnpm/action-setup@v4 27 | - uses: actions/setup-node@v4 28 | with: 29 | node-version: 22 30 | cache: 'pnpm' 31 | 32 | - run: pnpm install --frozen-lockfile 33 | - run: pnpm lint 34 | 35 | test: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - uses: pnpm/action-setup@v4 40 | - uses: actions/setup-node@v4 41 | with: 42 | node-version: 22 43 | cache: 'pnpm' 44 | 45 | - run: pnpm install --frozen-lockfile 46 | - run: pnpm test 47 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | create-github-release: 10 | permissions: 11 | contents: write 12 | runs-on: ubuntu-latest 13 | if: startsWith(github.ref, 'refs/tags/v') 14 | steps: 15 | - name: Calculate release name 16 | run: | 17 | GITHUB_REF=${{ github.ref }} 18 | RELEASE_NAME=${GITHUB_REF#"refs/tags/"} 19 | echo "RELEASE_NAME=${RELEASE_NAME}" >> $GITHUB_ENV 20 | 21 | - name: Publish release 22 | uses: actions/create-release@v1 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | tag_name: ${{ github.ref }} 27 | release_name: ${{ env.RELEASE_NAME }} 28 | draft: false 29 | prerelease: false 30 | 31 | publish-npm-release: 32 | runs-on: ubuntu-latest 33 | permissions: 34 | contents: read 35 | id-token: write 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: pnpm/action-setup@v4 39 | - uses: actions/setup-node@v4 40 | with: 41 | node-version: 22 42 | cache: 'pnpm' 43 | registry-url: 'https://registry.npmjs.org' 44 | 45 | - run: pnpm install --frozen-lockfile 46 | - run: npm publish --provenance --access public 47 | env: 48 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 49 | -------------------------------------------------------------------------------- /src/unformatter.test.ts: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, expect, test } from 'vitest'; 2 | 3 | import { de, es, store } from './index'; 4 | import { uncompactNumber } from './unformatter'; 5 | 6 | describe('uncompactNumber', () => { 7 | beforeEach(() => { 8 | store.reset(); 9 | store.register([es, de]); 10 | }); 11 | 12 | test('should uncompact basic numbers', () => { 13 | expect(uncompactNumber('1.2K')).toBe(1200); 14 | expect(uncompactNumber('1.5M')).toBe(1500000); 15 | expect(uncompactNumber('1B')).toBe(1000000000); 16 | expect(uncompactNumber('1T')).toBe(1000000000000); 17 | }); 18 | 19 | test('should handle negative numbers', () => { 20 | expect(uncompactNumber('-1.2K')).toBe(-1200); 21 | expect(uncompactNumber('-1.5M')).toBe(-1500000); 22 | }); 23 | 24 | test('should handle numbers without symbols', () => { 25 | expect(uncompactNumber('123')).toBe(123); 26 | expect(uncompactNumber('-456')).toBe(-456); 27 | }); 28 | 29 | test('should handle long styles', () => { 30 | expect(uncompactNumber('1.2 thousand')).toBe(1200); 31 | expect(uncompactNumber('2 million')).toBe(2000000); 32 | }); 33 | 34 | test('should handle different locales', () => { 35 | expect(uncompactNumber('1.2 mil', 'es')).toBe(1200); 36 | expect(uncompactNumber('1.2 Tsd.', 'de')).toBe(1200); 37 | }); 38 | 39 | test('should throw an error for invalid input', () => { 40 | expect(() => uncompactNumber('')).toThrow('Input must be a non-empty string.'); 41 | expect(() => uncompactNumber('invalid')).toThrow('Invalid number format.'); 42 | expect(() => uncompactNumber('1.2X')).toThrow('Unknown symbol: "x"'); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@se-oss/compact-number", 3 | "version": "1.0.0", 4 | "description": "A lightweight library for compact number formatting and parsing.", 5 | "keywords": [ 6 | "number", 7 | "format", 8 | "unformat", 9 | "compact", 10 | "abbreviate", 11 | "intl", 12 | "i18n", 13 | "locale" 14 | ], 15 | "homepage": "https://github.com/shahradelahi/compact-number", 16 | "repository": "github:shahradelahi/compact-number", 17 | "license": "MIT", 18 | "author": "Shahrad Elahi (https://github.com/shahradelahi)", 19 | "type": "module", 20 | "exports": { 21 | ".": { 22 | "import": "./dist/index.js", 23 | "default": "./dist/index.cjs" 24 | } 25 | }, 26 | "main": "dist/index.js", 27 | "types": "dist/index.d.ts", 28 | "files": [ 29 | "dist/**", 30 | "!**/*.d.cts" 31 | ], 32 | "scripts": { 33 | "bench": "vitest bench --run", 34 | "build": "pnpm typecheck && tsup", 35 | "clean": "git clean -dfx node_modules dist .tsbuildinfo", 36 | "dev": "tsup --watch", 37 | "format": "prettier --write .", 38 | "format:check": "prettier --check .", 39 | "generate:locales": "tsx scripts/generate-locales.ts", 40 | "lint": "pnpm typecheck && eslint .", 41 | "lint:fix": "eslint --fix .", 42 | "prepublishOnly": "pnpm build && pnpm lint && pnpm format:check && pnpm test", 43 | "test": "vitest --run", 44 | "typecheck": "tsc --noEmit" 45 | }, 46 | "prettier": "@shahrad/prettier-config", 47 | "devDependencies": { 48 | "@shahrad/eslint-config": "^1.0.0", 49 | "@shahrad/prettier-config": "^1.2.2", 50 | "@shahrad/tsconfig": "^1.2.0", 51 | "@types/node": "^24.3.0", 52 | "cldr-numbers-full": "^47.0.0", 53 | "eslint": "^9.34.0", 54 | "globals": "^16.3.0", 55 | "prettier": "^3.6.2", 56 | "tsup": "^8.5.0", 57 | "tsx": "^4.20.6", 58 | "typescript": "^5.9.2", 59 | "vitest": "^3.2.4" 60 | }, 61 | "packageManager": "pnpm@10.15.0" 62 | } 63 | -------------------------------------------------------------------------------- /src/locales/hi.ts: -------------------------------------------------------------------------------- 1 | import type { LocaleData } from '@/typings'; 2 | 3 | export const hi: LocaleData = { 4 | hi: { 5 | locale: 'hi', 6 | numbers: { 7 | decimal: { 8 | short: [ 9 | [1000, { one: ['0 हज़ार', 1], other: ['0 हज़ार', 1] }], 10 | [10000, { one: ['00 हज़ार', 2], other: ['00 हज़ार', 2] }], 11 | [100000, { one: ['0 लाख', 1], other: ['0 लाख', 1] }], 12 | [1000000, { one: ['00 लाख', 2], other: ['00 लाख', 2] }], 13 | [10000000, { one: ['0 क॰', 1], other: ['0 क॰', 1] }], 14 | [100000000, { one: ['00 क॰', 2], other: ['00 क॰', 2] }], 15 | [1000000000, { one: ['0 अ॰', 1], other: ['0 अ॰', 1] }], 16 | [10000000000, { one: ['00 अ॰', 2], other: ['00 अ॰', 2] }], 17 | [100000000000, { one: ['0 ख॰', 1], other: ['0 ख॰', 1] }], 18 | [1000000000000, { one: ['00 ख॰', 2], other: ['00 ख॰', 2] }], 19 | [10000000000000, { one: ['0 नील', 1], other: ['0 नील', 1] }], 20 | [100000000000000, { one: ['00 नील', 2], other: ['00 नील', 2] }], 21 | ], 22 | long: [ 23 | [1000, { one: ['0 हज़ार', 1], other: ['0 हज़ार', 1] }], 24 | [10000, { one: ['00 हज़ार', 2], other: ['00 हज़ार', 2] }], 25 | [100000, { one: ['0 लाख', 1], other: ['0 लाख', 1] }], 26 | [1000000, { one: ['00 लाख', 2], other: ['00 लाख', 2] }], 27 | [10000000, { one: ['0 करोड़', 1], other: ['0 करोड़', 1] }], 28 | [100000000, { one: ['00 करोड़', 2], other: ['00 करोड़', 2] }], 29 | [1000000000, { one: ['0 अरब', 1], other: ['0 अरब', 1] }], 30 | [10000000000, { one: ['00 अरब', 2], other: ['00 अरब', 2] }], 31 | [100000000000, { one: ['0 खरब', 1], other: ['0 खरब', 1] }], 32 | [1000000000000, { one: ['00 खरब', 2], other: ['00 खरब', 2] }], 33 | [10000000000000, { one: ['000 खरब', 3], other: ['000 खरब', 3] }], 34 | [100000000000000, { one: ['0000 खरब', 4], other: ['0000 खरब', 4] }], 35 | ], 36 | }, 37 | }, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /src/locales/en.ts: -------------------------------------------------------------------------------- 1 | import type { LocaleData } from '../typings'; 2 | 3 | export const en: LocaleData = { 4 | en: { 5 | locale: 'en', 6 | numbers: { 7 | decimal: { 8 | long: [ 9 | [1000, { one: ['0 thousand', 1], other: ['0 thousand', 1] }], 10 | [10000, { one: ['00 thousand', 2], other: ['00 thousand', 2] }], 11 | [100000, { one: ['000 thousand', 3], other: ['000 thousand', 3] }], 12 | [1000000, { one: ['0 million', 1], other: ['0 million', 1] }], 13 | [10000000, { one: ['00 million', 2], other: ['00 million', 2] }], 14 | [100000000, { one: ['000 million', 3], other: ['000 million', 3] }], 15 | [1000000000, { one: ['0 billion', 1], other: ['0 billion', 1] }], 16 | [10000000000, { one: ['00 billion', 2], other: ['00 billion', 2] }], 17 | [100000000000, { one: ['000 billion', 3], other: ['000 billion', 3] }], 18 | [1000000000000, { one: ['0 trillion', 1], other: ['0 trillion', 1] }], 19 | [10000000000000, { one: ['00 trillion', 2], other: ['00 trillion', 2] }], 20 | [100000000000000, { one: ['000 trillion', 3], other: ['000 trillion', 3] }], 21 | ], 22 | short: [ 23 | [1000, { one: ['0K', 1], other: ['0K', 1] }], 24 | [10000, { one: ['00K', 2], other: ['00K', 2] }], 25 | [100000, { one: ['000K', 3], other: ['000K', 3] }], 26 | [1000000, { one: ['0M', 1], other: ['0M', 1] }], 27 | [10000000, { one: ['00M', 2], other: ['00M', 2] }], 28 | [100000000, { one: ['000M', 3], other: ['000M', 3] }], 29 | [1000000000, { one: ['0B', 1], other: ['0B', 1] }], 30 | [10000000000, { one: ['00B', 2], other: ['00B', 2] }], 31 | [100000000000, { one: ['000B', 3], other: ['000B', 3] }], 32 | [1000000000000, { one: ['0T', 1], other: ['0T', 1] }], 33 | [10000000000000, { one: ['00T', 2], other: ['00T', 2] }], 34 | [100000000000000, { one: ['000T', 3], other: ['000T', 3] }], 35 | ], 36 | }, 37 | }, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /src/locales/fr.ts: -------------------------------------------------------------------------------- 1 | import type { LocaleData } from '@/typings'; 2 | 3 | export const fr: LocaleData = { 4 | fr: { 5 | locale: 'fr', 6 | numbers: { 7 | decimal: { 8 | short: [ 9 | [1000, { one: ['0 k', 1], other: ['0 k', 1] }], 10 | [10000, { one: ['00 k', 2], other: ['00 k', 2] }], 11 | [100000, { one: ['000 k', 3], other: ['000 k', 3] }], 12 | [1000000, { one: ['0 M', 1], other: ['0 M', 1] }], 13 | [10000000, { one: ['00 M', 2], other: ['00 M', 2] }], 14 | [100000000, { one: ['000 M', 3], other: ['000 M', 3] }], 15 | [1000000000, { one: ['0 Md', 1], other: ['0 Md', 1] }], 16 | [10000000000, { one: ['00 Md', 2], other: ['00 Md', 2] }], 17 | [100000000000, { one: ['000 Md', 3], other: ['000 Md', 3] }], 18 | [1000000000000, { one: ['0 Bn', 1], other: ['0 Bn', 1] }], 19 | [10000000000000, { one: ['00 Bn', 2], other: ['00 Bn', 2] }], 20 | [100000000000000, { one: ['000 Bn', 3], other: ['000 Bn', 3] }], 21 | ], 22 | long: [ 23 | [1000, { one: ['0 millier', 1], other: ['0 mille', 1] }], 24 | [10000, { one: ['00 mille', 2], other: ['00 mille', 2] }], 25 | [100000, { one: ['000 mille', 3], other: ['000 mille', 3] }], 26 | [1000000, { one: ['0 million', 1], other: ['0 millions', 1] }], 27 | [10000000, { one: ['00 million', 2], other: ['00 millions', 2] }], 28 | [100000000, { one: ['000 million', 3], other: ['000 millions', 3] }], 29 | [1000000000, { one: ['0 milliard', 1], other: ['0 milliards', 1] }], 30 | [10000000000, { one: ['00 milliard', 2], other: ['00 milliards', 2] }], 31 | [100000000000, { one: ['000 milliard', 3], other: ['000 milliards', 3] }], 32 | [1000000000000, { one: ['0 billion', 1], other: ['0 billions', 1] }], 33 | [10000000000000, { one: ['00 billion', 2], other: ['00 billions', 2] }], 34 | [100000000000000, { one: ['000 billion', 3], other: ['000 billions', 3] }], 35 | ], 36 | }, 37 | }, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /src/locales/es.ts: -------------------------------------------------------------------------------- 1 | import type { LocaleData } from '@/typings'; 2 | 3 | export const es: LocaleData = { 4 | es: { 5 | locale: 'es', 6 | numbers: { 7 | decimal: { 8 | short: [ 9 | [1000, { one: ['0 mil', 1], other: ['0 mil', 1] }], 10 | [10000, { one: ['00 mil', 2], other: ['00 mil', 2] }], 11 | [100000, { one: ['000 mil', 3], other: ['000 mil', 3] }], 12 | [1000000, { one: ['0 M', 1], other: ['0 M', 1] }], 13 | [10000000, { one: ['00 M', 2], other: ['00 M', 2] }], 14 | [100000000, { one: ['000 M', 3], other: ['000 M', 3] }], 15 | [1000000000, { one: ['0000 M', 4], other: ['0000 M', 4] }], 16 | [10000000000, { one: ['00 mil M', 2], other: ['00 mil M', 2] }], 17 | [100000000000, { one: ['000 mil M', 3], other: ['000 mil M', 3] }], 18 | [1000000000000, { one: ['0 B', 1], other: ['0 B', 1] }], 19 | [10000000000000, { one: ['00 B', 2], other: ['00 B', 2] }], 20 | [100000000000000, { one: ['000 B', 3], other: ['000 B', 3] }], 21 | ], 22 | long: [ 23 | [1000, { one: ['0 mil', 1], other: ['0 mil', 1] }], 24 | [10000, { one: ['00 mil', 2], other: ['00 mil', 2] }], 25 | [100000, { one: ['000 mil', 3], other: ['000 mil', 3] }], 26 | [1000000, { one: ['0 millón', 1], other: ['0 millones', 1] }], 27 | [10000000, { one: ['00 millones', 2], other: ['00 millones', 2] }], 28 | [100000000, { one: ['000 millones', 3], other: ['000 millones', 3] }], 29 | [1000000000, { one: ['0 mil millones', 1], other: ['0 mil millones', 1] }], 30 | [10000000000, { one: ['00 mil millones', 2], other: ['00 mil millones', 2] }], 31 | [100000000000, { one: ['000 mil millones', 3], other: ['000 mil millones', 3] }], 32 | [1000000000000, { one: ['0 billón', 1], other: ['0 billones', 1] }], 33 | [10000000000000, { one: ['00 billones', 2], other: ['00 billones', 2] }], 34 | [100000000000000, { one: ['000 billones', 3], other: ['000 billones', 3] }], 35 | ], 36 | }, 37 | }, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /src/typings.ts: -------------------------------------------------------------------------------- 1 | export type RoundingMode = 'round' | 'floor' | 'ceil'; 2 | 3 | export interface CompactNumberOptions { 4 | /** 5 | * The locale to use for formatting. Defaults to 'en'. 6 | */ 7 | locale?: string; 8 | /** 9 | * Custom locale data to register for the current call. This will override any existing locale data. 10 | */ 11 | localeData?: LocaleData; 12 | /** 13 | * The formatting style to use. 'short' for compact abbreviations (e.g., 1.2K), 'long' for full words (e.g., 1.2 thousand). Defaults to 'short'. 14 | */ 15 | style?: 'short' | 'long'; 16 | /** 17 | * The minimum number of fraction digits to use. Defaults to 0. 18 | */ 19 | minimumFractionDigits?: number; 20 | /** 21 | * The maximum number of fraction digits to use. Defaults to 1. 22 | */ 23 | maximumFractionDigits?: number; 24 | /** 25 | * The rounding mode to apply. Defaults to 'round'. 26 | */ 27 | roundingMode?: RoundingMode; 28 | /** 29 | * A threshold value used for tier-jumping logic. Defaults to 0.0005. 30 | */ 31 | threshold?: number; 32 | } 33 | 34 | /** 35 | * A tuple representing the format string and the number of digits for a number format. 36 | * @example ['0K', 1] 37 | */ 38 | export type FormatTuple = [string, number]; 39 | 40 | /** 41 | * An object containing pluralization rules for a number format. 42 | */ 43 | export interface PluralizedFormat { 44 | one: FormatTuple; 45 | other: FormatTuple; 46 | } 47 | 48 | /** 49 | * A rule for formatting a number, consisting of a threshold and the corresponding format. 50 | * @example [1000, { one: ['0K', 1], other: ['0K', 1] }] 51 | */ 52 | export type FormatRule = [number, PluralizedFormat]; 53 | 54 | /** 55 | * An array of formatting rules for a specific style (e.g., 'short' or 'long'). 56 | */ 57 | export type FormatRules = Array; 58 | 59 | export interface Locale { 60 | numbers: { 61 | decimal: { 62 | long: FormatRules; 63 | short: FormatRules; 64 | }; 65 | }; 66 | locale: string; 67 | parentLocale?: string; 68 | } 69 | 70 | export interface LocaleData { 71 | [locale: string]: Locale; 72 | } 73 | -------------------------------------------------------------------------------- /src/locales/de.ts: -------------------------------------------------------------------------------- 1 | import type { LocaleData } from '@/typings'; 2 | 3 | export const de: LocaleData = { 4 | de: { 5 | locale: 'de', 6 | numbers: { 7 | decimal: { 8 | short: [ 9 | [1000, { one: ['0 Tsd.', 1], other: ['0 Tsd.', 1] }], 10 | [10000, { one: ['00 Tsd.', 2], other: ['00 Tsd.', 2] }], 11 | [100000, { one: ['000 Tsd.', 3], other: ['000 Tsd.', 3] }], 12 | [1000000, { one: ["0 Mio'.'", 1], other: ["0 Mio'.'", 1] }], 13 | [10000000, { one: ["00 Mio'.'", 2], other: ["00 Mio'.'", 2] }], 14 | [100000000, { one: ["000 Mio'.'", 3], other: ["000 Mio'.'", 3] }], 15 | [1000000000, { one: ["0 Mrd'.'", 1], other: ["0 Mrd'.'", 1] }], 16 | [10000000000, { one: ["00 Mrd'.'", 2], other: ["00 Mrd'.'", 2] }], 17 | [100000000000, { one: ["000 Mrd'.'", 3], other: ["000 Mrd'.'", 3] }], 18 | [1000000000000, { one: ["0 Bio'.'", 1], other: ["0 Bio'.'", 1] }], 19 | [10000000000000, { one: ["00 Bio'.'", 2], other: ["00 Bio'.'", 2] }], 20 | [100000000000000, { one: ["000 Bio'.'", 3], other: ["000 Bio'.'", 3] }], 21 | ], 22 | long: [ 23 | [1000, { one: ['0 Tausend', 1], other: ['0 Tausend', 1] }], 24 | [10000, { one: ['00 Tausend', 2], other: ['00 Tausend', 2] }], 25 | [100000, { one: ['000 Tausend', 3], other: ['000 Tausend', 3] }], 26 | [1000000, { one: ['0 Million', 1], other: ['0 Millionen', 1] }], 27 | [10000000, { one: ['00 Millionen', 2], other: ['00 Millionen', 2] }], 28 | [100000000, { one: ['000 Millionen', 3], other: ['000 Millionen', 3] }], 29 | [1000000000, { one: ['0 Milliarde', 1], other: ['0 Milliarden', 1] }], 30 | [10000000000, { one: ['00 Milliarden', 2], other: ['00 Milliarden', 2] }], 31 | [100000000000, { one: ['000 Milliarden', 3], other: ['000 Milliarden', 3] }], 32 | [1000000000000, { one: ['0 Billion', 1], other: ['0 Billionen', 1] }], 33 | [10000000000000, { one: ['00 Billionen', 2], other: ['00 Billionen', 2] }], 34 | [100000000000000, { one: ['000 Billionen', 3], other: ['000 Billionen', 3] }], 35 | ], 36 | }, 37 | }, 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional stylelint cache 57 | .stylelintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variable files 69 | .env 70 | .env.* 71 | !.env.example 72 | 73 | # parcel-bundler cache (https://parceljs.org/) 74 | .cache 75 | .parcel-cache 76 | 77 | # Next.js build output 78 | .next 79 | out 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and not Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # vuepress v2.x temp and cache directory 95 | .temp 96 | .cache 97 | 98 | # Sveltekit cache directory 99 | .svelte-kit/ 100 | 101 | # vitepress build output 102 | **/.vitepress/dist 103 | 104 | # vitepress cache directory 105 | **/.vitepress/cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # Firebase cache directory 120 | .firebase/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v3 129 | .pnp.* 130 | .yarn/* 131 | !.yarn/patches 132 | !.yarn/plugins 133 | !.yarn/releases 134 | !.yarn/sdks 135 | !.yarn/versions 136 | 137 | # Vite logs files 138 | vite.config.js.timestamp-* 139 | vite.config.ts.timestamp-* 140 | -------------------------------------------------------------------------------- /src/cldr-utils.ts: -------------------------------------------------------------------------------- 1 | import type { FormatRule, FormatRules, LocaleData } from '@/typings'; 2 | 3 | /** 4 | * Transforms raw CLDR number formatting data into the internal structure. 5 | * @param cldrFormat The raw CLDR decimal format object. 6 | * @returns The transformed format rules. 7 | */ 8 | function transformCLDRData(cldrFormat: Record): FormatRules { 9 | const rules: FormatRules = []; 10 | for (const key in cldrFormat) { 11 | const parts = key.split('-'); 12 | if (parts.length < 2) continue; 13 | 14 | const power = parts[0]; 15 | const plural = parts[parts.length - 1]; 16 | 17 | if (plural !== 'one' && plural !== 'other') continue; 18 | 19 | const numPower = Number(power); 20 | if (numPower > Number.MAX_SAFE_INTEGER) { 21 | continue; 22 | } 23 | 24 | const formatString = cldrFormat[key]!; 25 | const numZeros = (formatString.match(/0/g) || []).length; 26 | 27 | let rule = rules.find((r) => r[0] === numPower); 28 | if (!rule) { 29 | rule = [ 30 | numPower, 31 | { 32 | one: ['', 0], 33 | other: ['', 0], 34 | }, 35 | ] as FormatRule; 36 | rules.push(rule); 37 | } 38 | 39 | rule[1][plural] = [formatString, numZeros]; 40 | } 41 | return rules.sort((a, b) => a[0] - b[0]); 42 | } 43 | 44 | /** 45 | * Parses raw CLDR data and transforms it into the application's internal format. 46 | * @param cldrData The raw CLDR data object. 47 | * @returns The transformed locale data. 48 | */ 49 | export function parseCLDR(cldrData: any): LocaleData { 50 | const localeKey = Object.keys(cldrData.main)[0]!; 51 | const cldrNumbers = cldrData.main[localeKey].numbers; 52 | const latnFormats = cldrNumbers['decimalFormats-numberSystem-latn']; 53 | 54 | const transformedData: LocaleData = { 55 | [localeKey]: { 56 | locale: localeKey, 57 | numbers: { 58 | decimal: { 59 | short: transformCLDRData(latnFormats.short.decimalFormat), 60 | long: transformCLDRData(latnFormats.long.decimalFormat), 61 | }, 62 | }, 63 | }, 64 | }; 65 | 66 | // Special case for German 'Tsd.' abbreviation 67 | if (localeKey === 'de') { 68 | const shortRules = transformedData['de']!.numbers.decimal.short; 69 | const thousandRule = shortRules.find((r) => r[0] === 1000); 70 | if (thousandRule) { 71 | thousandRule[1].one = ['0 Tsd.', 1]; 72 | thousandRule[1].other = ['0 Tsd.', 1]; 73 | } 74 | const tenThousandRule = shortRules.find((r) => r[0] === 10000); 75 | if (tenThousandRule) { 76 | tenThousandRule[1].one = ['00 Tsd.', 2]; 77 | tenThousandRule[1].other = ['00 Tsd.', 2]; 78 | } 79 | const hundredThousandRule = shortRules.find((r) => r[0] === 100000); 80 | if (hundredThousandRule) { 81 | hundredThousandRule[1].one = ['000 Tsd.', 3]; 82 | hundredThousandRule[1].other = ['000 Tsd.', 3]; 83 | } 84 | } 85 | 86 | return transformedData; 87 | } 88 | -------------------------------------------------------------------------------- /src/unformatter.ts: -------------------------------------------------------------------------------- 1 | import { CompactNumberError } from './errors'; 2 | import { store } from './store'; 3 | import type { FormatRules, Locale } from './typings'; 4 | 5 | /** 6 | * Parses a compacted number string back into a number. 7 | * @param value The compacted string to parse. 8 | * @param locale The locale to use for parsing symbols. Defaults to 'en'. 9 | * @returns The uncompacted number. 10 | * @throws {CompactNumberError} If the input is not a non-empty string, has an invalid number format, or contains an unknown symbol. 11 | */ 12 | export function uncompactNumber(value: string, locale = 'en'): number { 13 | if (typeof value !== 'string' || !value.trim()) { 14 | throw new CompactNumberError('Input must be a non-empty string.'); 15 | } 16 | 17 | const symbolMap = getSymbolMap(locale); 18 | 19 | const numberPartMatch = value.match(/[+-]?([0-9]*[.])?[0-9]+/); 20 | if (!numberPartMatch) { 21 | throw new CompactNumberError('Invalid number format.'); 22 | } 23 | const numberPart = parseFloat(numberPartMatch[0]); 24 | 25 | const symbolPart = value.replace(numberPartMatch[0], '').trim().toLowerCase(); 26 | 27 | if (!symbolPart) { 28 | return numberPart; 29 | } 30 | 31 | const divisor = symbolMap.get(symbolPart); 32 | if (!divisor) { 33 | throw new CompactNumberError(`Unknown symbol: "${symbolPart}"`); 34 | } 35 | 36 | return numberPart * divisor; 37 | } 38 | 39 | // Cache for locale-specific symbol maps. 40 | const symbolMapsCache = new Map>(); 41 | 42 | function createSymbolMap(localeData: Locale): Map { 43 | const symbolMap = new Map(); 44 | 45 | function addSymbols(rules: FormatRules) { 46 | for (const [divisor, formatInfo] of rules) { 47 | const symbol = formatInfo.one[0].replace(/0+/, '').trim(); 48 | const lowerSymbol = symbol.toLowerCase(); 49 | if (symbol && !symbolMap.has(lowerSymbol)) { 50 | symbolMap.set(lowerSymbol, divisor); 51 | } 52 | 53 | const pluralSymbol = formatInfo.other[0].replace(/0+/, '').trim(); 54 | const lowerPluralSymbol = pluralSymbol.toLowerCase(); 55 | if (pluralSymbol && !symbolMap.has(lowerPluralSymbol)) { 56 | symbolMap.set(lowerPluralSymbol, divisor); 57 | } 58 | } 59 | } 60 | 61 | if (localeData.numbers?.decimal) { 62 | addSymbols(localeData.numbers.decimal.short); 63 | addSymbols(localeData.numbers.decimal.long); 64 | } 65 | 66 | return symbolMap; 67 | } 68 | 69 | function getSymbolMap(locale = 'en'): Map { 70 | if (symbolMapsCache.has(locale)) { 71 | return symbolMapsCache.get(locale)!; 72 | } 73 | 74 | const localeData = store.get(locale); 75 | if (!localeData) { 76 | const enLocaleData = store.get('en'); 77 | if (!enLocaleData) { 78 | throw new CompactNumberError('Default locale "en" is not registered.'); 79 | } 80 | const enSymbolMap = createSymbolMap(enLocaleData); 81 | symbolMapsCache.set('en', enSymbolMap); 82 | return enSymbolMap; 83 | } 84 | 85 | const newSymbolMap = createSymbolMap(localeData); 86 | symbolMapsCache.set(locale, newSymbolMap); 87 | return newSymbolMap; 88 | } 89 | 90 | // Pre-warm the cache with the default 'en' locale. 91 | const enLocaleData = store.get('en'); 92 | if (enLocaleData) { 93 | symbolMapsCache.set('en', createSymbolMap(enLocaleData)); 94 | } 95 | -------------------------------------------------------------------------------- /scripts/generate-locales.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises'; 2 | import path from 'node:path'; 3 | import { fileURLToPath } from 'node:url'; 4 | import prettier from 'prettier'; 5 | 6 | import { parseCLDR } from '@/cldr-utils'; 7 | 8 | // Path to the CLDR data package 9 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 10 | const CLDR_NUMBERS_FULL_PATH = path.dirname( 11 | fileURLToPath(import.meta.resolve('cldr-numbers-full/package.json')) 12 | ); 13 | 14 | const LOCALES_TO_GENERATE = [ 15 | 'de', // German 16 | 'es', // Spanish 17 | 'fr', // French 18 | 'hi', // Hindi 19 | 'ja', // Japanese 20 | 'zh', // Chinese 21 | ]; 22 | 23 | const prettierConfig = await prettier.resolveConfig('@shahrad/prettier-config'); 24 | 25 | async function writeTypescriptFile(filePath: string, content: string) { 26 | const formattedContent = await prettier.format(content, { 27 | ...prettierConfig, 28 | parser: 'typescript', 29 | }); 30 | 31 | await fs.writeFile(filePath, formattedContent); 32 | } 33 | 34 | async function generateLocales() { 35 | console.log('Starting locale generation...'); 36 | 37 | const localesDir = path.resolve(__dirname, '../src/locales'); 38 | await fs.mkdir(localesDir, { recursive: true }); 39 | 40 | for (const locale of LOCALES_TO_GENERATE) { 41 | const filePath = path.join(CLDR_NUMBERS_FULL_PATH, `main/${locale}/numbers.json`); 42 | const fileContent = await fs.readFile(filePath, 'utf8'); 43 | const cldrData = JSON.parse(fileContent); 44 | 45 | const transformedData = parseCLDR(cldrData); 46 | const localeObject = transformedData[locale]; 47 | 48 | const outputFilePath = path.join(localesDir, `${locale}.ts`); 49 | let fileContentString; 50 | 51 | if ( 52 | localeObject && 53 | JSON.stringify(localeObject.numbers.decimal.short) === 54 | JSON.stringify(localeObject.numbers.decimal.long) 55 | ) { 56 | const decimalValues = JSON.stringify(localeObject.numbers.decimal.short); 57 | fileContentString = `import type { FormatRules, LocaleData } from '@/typings'; 58 | 59 | const decimalValues: FormatRules = ${decimalValues}; 60 | 61 | export const ${locale}: LocaleData = { 62 | '${locale}': { 63 | locale: '${locale}', 64 | numbers: { 65 | decimal: { 66 | short: decimalValues, 67 | long: decimalValues, 68 | }, 69 | }, 70 | }, 71 | }; 72 | `; 73 | } else { 74 | fileContentString = `import type { LocaleData } from '@/typings'; 75 | 76 | export const ${locale}: LocaleData = ${JSON.stringify(transformedData)}; 77 | `; 78 | } 79 | 80 | await writeTypescriptFile(outputFilePath, fileContentString); 81 | 82 | console.log(`Generated and formatted locale file: ${outputFilePath}`); 83 | } 84 | 85 | await updateLocalesIndex(localesDir); 86 | console.log('Locale generation complete.'); 87 | } 88 | 89 | async function updateLocalesIndex(localesDir: string) { 90 | const files = await fs.readdir(localesDir); 91 | const indexFilePath = path.join(localesDir, 'index.ts'); 92 | 93 | // Filter out index.ts and non-ts files 94 | const localeFiles = files 95 | .filter((file) => file.endsWith('.ts') && file !== 'index.ts' && file !== 'en.ts') 96 | .map((file) => file.replace('.ts', '')); 97 | 98 | const exports = localeFiles.map((locale) => `export * from './${locale}';`).join('\n'); 99 | const indexContent = `export * from './en'; 100 | ${exports} 101 | `; 102 | 103 | await writeTypescriptFile(indexFilePath, indexContent); 104 | console.log('Updated and formatted locales/index.ts'); 105 | } 106 | 107 | generateLocales().catch((error) => { 108 | console.error('Error generating locales:', error); 109 | process.exit(1); 110 | }); 111 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { RoundingMode } from './typings'; 2 | 3 | /** 4 | * Rounds a decimal number to a specified precision, handling floating-point inaccuracies. 5 | * @param value The number to round. 6 | * @param precision The number of decimal places. 7 | * @returns The rounded number. 8 | */ 9 | export function roundDecimal(value: number, precision: number): number { 10 | if (!Number.isFinite(value) || !Number.isInteger(precision) || precision < 0) { 11 | return value; // Or throw an error, depending on desired behavior for invalid input 12 | } 13 | 14 | const sign = Math.sign(value); 15 | const absValue = Math.abs(value); 16 | 17 | // Using string manipulation to avoid floating-point issues with multiplication 18 | const scaledValue = Number(`${absValue}e${precision}`); 19 | const roundedValue = Math.round(scaledValue); 20 | const unscaledValue = Number(`${roundedValue}e-${precision}`); 21 | 22 | return unscaledValue * sign; 23 | } 24 | 25 | /** 26 | * Rounds a number to a specified precision using a given rounding mode. 27 | * @param value The number to round. 28 | * @param precision The number of decimal places. 29 | * @param mode The rounding mode. 30 | * @returns The rounded number. 31 | */ 32 | export function round(value: number, precision: number, mode: RoundingMode): number { 33 | if (!Number.isFinite(value) || !Number.isInteger(precision) || precision < 0) { 34 | return value; // Or throw an error 35 | } 36 | 37 | const multiplier = 10 ** precision; 38 | 39 | switch (mode) { 40 | case 'floor': 41 | return Math.floor(value * multiplier) / multiplier; 42 | case 'ceil': 43 | return Math.ceil(value * multiplier) / multiplier; 44 | case 'round': 45 | return roundDecimal(value, precision); 46 | default: 47 | // This should not be reached if RoundingMode is correctly typed, 48 | // but it's good practice to handle unexpected values. 49 | throw new Error(`Invalid rounding mode: ${mode}`); 50 | } 51 | } 52 | 53 | /** 54 | * Pre-scales a number based on the CLDR rule's digit count. 55 | * This is a crucial step for correct rounding and formatting. 56 | * e.g., (11234, 1000, 1) -> 1.1234 57 | * e.g., (11234, 10000, 2) -> 1.1234 58 | * 59 | * @param num The number to scale. 60 | * @param divisor The divisor from the locale rule. 61 | * @param numberOfDigits The number of digits from the locale rule. 62 | * @returns The pre-scaled number. 63 | */ 64 | export function preScaleNumber(num: number, divisor: number, numberOfDigits: number): number { 65 | return (num / divisor) * 10 ** (numberOfDigits - 1); 66 | } 67 | 68 | /** 69 | * Normalizes a locale string to a consistent format (e.g., 'en-US'). 70 | * @param locale The locale string or array of strings to normalize. 71 | * @returns The normalized locale string. 72 | */ 73 | export function normalizeLocale(locale: string | string[]): string { 74 | const localeString = Array.isArray(locale) ? locale[0] : locale; 75 | if (!localeString) { 76 | return ''; 77 | } 78 | return localeString.replace(/_/, '-').toLowerCase(); 79 | } 80 | 81 | /** 82 | * Cleans up a format string by removing special characters, like quotes. 83 | * e.g., "'t.'" -> "t." 84 | * @param str The string to polish. 85 | * @returns The polished string. 86 | */ 87 | export function polishString(str: string): string { 88 | return str.replace(/'/g, ''); 89 | } 90 | 91 | /** 92 | * Custom toFixed function that rounds to the nearest number, 93 | * and if the number is halfway, it rounds away from zero (like Number.prototype.toFixed). 94 | * @param decimal The number to format. 95 | * @param significantDigits The number of digits to appear after the decimal point. 96 | * @returns The number rounded to the specified significant digits. 97 | */ 98 | export function toFixed(decimal: number, significantDigits: number): number { 99 | const powOf10 = Math.pow(10, significantDigits); 100 | const scaled = decimal * powOf10; 101 | // Custom rounding to handle .5 away from zero for both positive and negative numbers 102 | const rounded = Math.round(Math.abs(scaled) + Number.EPSILON) * Math.sign(scaled); 103 | return rounded / powOf10; 104 | } 105 | 106 | /** 107 | * Efficiently parses a number string to extract its integer and fractional parts. 108 | * Avoids the overhead of String.prototype.split() by using indexOf() and substring(). 109 | * @param formattedNumberString The number string to parse (e.g., "123.45", "123"). 110 | * @returns An object containing the integerPart and fractionalPart. 111 | */ 112 | export function parseNumberString(formattedNumberString: string): { 113 | integerPart: string; 114 | fractionalPart: string; 115 | } { 116 | const dotIndex = formattedNumberString.indexOf('.'); 117 | if (dotIndex !== -1) { 118 | return { 119 | integerPart: formattedNumberString.substring(0, dotIndex), 120 | fractionalPart: formattedNumberString.substring(dotIndex + 1), 121 | }; 122 | } else { 123 | return { 124 | integerPart: formattedNumberString, 125 | fractionalPart: '', 126 | }; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/store.ts: -------------------------------------------------------------------------------- 1 | import { en } from '@/locales'; 2 | 3 | import { parseCLDR } from './cldr-utils'; 4 | import { CompactNumberError } from './errors'; 5 | import type { Locale, LocaleData } from './typings'; 6 | import { normalizeLocale } from './utils'; 7 | 8 | const defaultLocales: LocaleData = { 9 | ...en, 10 | }; 11 | 12 | /** 13 | * Manages the registration and retrieval of locale data for compact number formatting. 14 | * This store ensures that locale definitions are accessible throughout the application 15 | * and supports tree-shaking by allowing explicit registration of needed locales. 16 | */ 17 | class LocaleStore { 18 | #locales: LocaleData = { ...defaultLocales }; 19 | 20 | /** 21 | * Registers one or more locale data objects from raw CLDR JSON imports. 22 | * @param cldrData A single raw CLDR data object or an array of them. 23 | */ 24 | public registerFromCLDR(cldrData: any | any[]): void { 25 | const cldrDataArray = Array.isArray(cldrData) ? cldrData : [cldrData]; 26 | 27 | for (const data of cldrDataArray) { 28 | if (!data.main) continue; 29 | const transformedData = parseCLDR(data); 30 | this.register(transformedData); 31 | } 32 | } 33 | 34 | /** 35 | * (Node.js only) Registers all available locales from the `cldr-numbers-full` package. 36 | * This function dynamically reads and processes all locale files from the package. 37 | * It will throw an error if used in a non-Node.js environment. 38 | * @throws {CompactNumberError} If not in a Node.js environment or if `cldr-numbers-full` is not found. 39 | */ 40 | public async registerFullCLDR(): Promise { 41 | try { 42 | const { createRequire } = await import('node:module'); 43 | const fs = await import('node:fs/promises'); 44 | const path = await import('node:path'); 45 | 46 | const require = createRequire(import.meta.url); 47 | const cldrNumbersFullPath = path.dirname(require.resolve('cldr-numbers-full/package.json')); 48 | const cldrMainPath = path.join(cldrNumbersFullPath, 'main'); 49 | 50 | const localeDirs = await fs.readdir(cldrMainPath, { withFileTypes: true }); 51 | 52 | const localesToRegister = []; 53 | for (const dirent of localeDirs) { 54 | if (dirent.isDirectory()) { 55 | const localeId = dirent.name; 56 | const numbersJsonPath = path.join(cldrMainPath, localeId, 'numbers.json'); 57 | try { 58 | await fs.access(numbersJsonPath); 59 | const cldrData = require(numbersJsonPath); 60 | localesToRegister.push(cldrData); 61 | } catch { 62 | // Ignore directories that don't contain a numbers.json file 63 | } 64 | } 65 | } 66 | 67 | this.registerFromCLDR(localesToRegister); 68 | } catch (error) { 69 | throw new CompactNumberError( 70 | 'registerFullCLDR() is only supported in a Node.js environment and requires the "cldr-numbers-full" package to be installed.' 71 | ); 72 | } 73 | } 74 | 75 | /** 76 | * Registers one or more pre-formatted locale data objects with the store. 77 | * Existing locales with the same normalized key will be overwritten. 78 | * @param localeData A single LocaleData object or an array of LocaleData objects to register. 79 | */ 80 | public register(localeData: LocaleData | LocaleData[]): void { 81 | const localesToAdd = Array.isArray(localeData) ? localeData : [localeData]; 82 | for (const data of localesToAdd) { 83 | for (const [key, value] of Object.entries(data)) { 84 | this.#locales[normalizeLocale(key)] = value; 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * Retrieves the locale information for a given locale string. 91 | * If the exact locale is not found, it attempts to find a parent locale (e.g., 'en' for 'en-US'). 92 | * @param locale The locale string to retrieve (e.g., 'en', 'es-MX'). 93 | * @returns The Locale object if found, otherwise undefined. 94 | */ 95 | public get(locale: string): Locale | undefined { 96 | const normalized = normalizeLocale(locale); 97 | const localeInfo = this.#locales[normalized]; 98 | 99 | if (localeInfo) { 100 | return localeInfo; 101 | } 102 | 103 | // If not found, try to find a parent locale 104 | const parentLocaleKey = Object.keys(this.#locales).find((key) => 105 | normalized.startsWith(`${key}-`) 106 | ); 107 | if (parentLocaleKey) { 108 | return this.#locales[parentLocaleKey]; 109 | } 110 | 111 | return undefined; 112 | } 113 | 114 | /** 115 | * Returns an array of all currently registered locale keys. 116 | * @returns An array of strings, each representing a registered locale key. 117 | */ 118 | public getRegisteredLocales(): string[] { 119 | return Object.keys(this.#locales); 120 | } 121 | 122 | /** 123 | * Resets the store to its default state, containing only the 'en' locale. 124 | * All other registered locales will be removed. 125 | */ 126 | public reset(): void { 127 | this.#locales = { ...defaultLocales }; 128 | } 129 | } 130 | 131 | export const store = new LocaleStore(); 132 | -------------------------------------------------------------------------------- /src/formatter.ts: -------------------------------------------------------------------------------- 1 | import { CompactNumberError } from './errors'; 2 | import { store } from './store'; 3 | import type { CompactNumberOptions, FormatRule, Locale, RoundingMode } from './typings'; 4 | import { normalizeLocale, polishString, preScaleNumber, round } from './utils'; 5 | 6 | export function compactNumber(value: number | string, options: CompactNumberOptions = {}): string { 7 | const { 8 | locale = 'en', 9 | localeData: customLocaleData, 10 | style = 'short', 11 | minimumFractionDigits = 0, 12 | maximumFractionDigits = 1, 13 | roundingMode = 'round', 14 | threshold = 0.0005, 15 | } = options; 16 | 17 | if (customLocaleData) { 18 | store.register(customLocaleData); 19 | } 20 | 21 | const num = Number(value); 22 | if (Number.isNaN(num) || !Number.isFinite(num)) { 23 | if (value === null) return '0'; 24 | throw new CompactNumberError('Input must be a finite number.'); 25 | } 26 | 27 | if (maximumFractionDigits < 0 || minimumFractionDigits < 0) { 28 | throw new CompactNumberError('Fraction digits must be non-negative numbers.'); 29 | } 30 | 31 | if (minimumFractionDigits > maximumFractionDigits) { 32 | throw new CompactNumberError( 33 | 'minimumFractionDigits cannot be greater than maximumFractionDigits.' 34 | ); 35 | } 36 | 37 | const isNegative = num < 0; 38 | const absNum = Math.abs(num); 39 | 40 | const localeInfo = findLocaleData(locale); 41 | const rules = 42 | style === 'long' ? localeInfo.numbers.decimal.long : localeInfo.numbers.decimal.short; 43 | 44 | if (absNum < 1000) { 45 | const rounded = round(num, maximumFractionDigits, roundingMode); 46 | if (Math.abs(rounded) >= 1000) { 47 | return formatValue( 48 | rounded, 49 | rounded < 0, 50 | rules[0]!, 51 | minimumFractionDigits, 52 | maximumFractionDigits, 53 | roundingMode 54 | ); 55 | } 56 | return formatNumberString(rounded, minimumFractionDigits, maximumFractionDigits); 57 | } 58 | 59 | let matchingRule: FormatRule | undefined; 60 | let matchingRuleIndex = -1; 61 | for (let i = 0; i < rules.length; i++) { 62 | if (absNum >= rules[i]![0]) { 63 | matchingRule = rules[i]; 64 | matchingRuleIndex = i; 65 | } else { 66 | break; 67 | } 68 | } 69 | 70 | if (!matchingRule) { 71 | const rounded = round(num, maximumFractionDigits, roundingMode); 72 | return formatNumberString(rounded, minimumFractionDigits, maximumFractionDigits); 73 | } 74 | 75 | // Threshold-based tier-jumping logic 76 | const nextRule = rules[matchingRuleIndex + 1]; 77 | if (nextRule) { 78 | const [nextDivisor] = nextRule; 79 | if (1 - absNum / nextDivisor <= threshold) { 80 | matchingRule = nextRule; 81 | } 82 | } 83 | 84 | return formatValue( 85 | num, 86 | isNegative, 87 | matchingRule, 88 | minimumFractionDigits, 89 | maximumFractionDigits, 90 | roundingMode 91 | ); 92 | } 93 | 94 | function findLocaleData(locale: string): Locale { 95 | const normalized = normalizeLocale(locale); 96 | const localeInfo = store.get(normalized); 97 | if (!localeInfo) { 98 | throw new CompactNumberError( 99 | `Locale "${locale}" has not been registered. Please register it using "store.register()".` 100 | ); 101 | } 102 | return localeInfo; 103 | } 104 | 105 | function formatNumberString( 106 | value: number, 107 | minimumFractionDigits: number, 108 | maximumFractionDigits: number 109 | ): string { 110 | const fixedString = value.toFixed(maximumFractionDigits); 111 | const dotIndex = fixedString.indexOf('.'); 112 | 113 | if (dotIndex === -1) { 114 | if (minimumFractionDigits > 0) { 115 | return `${fixedString}.${'0'.repeat(minimumFractionDigits)}`; 116 | } 117 | return fixedString; 118 | } 119 | 120 | const integerPart = fixedString.substring(0, dotIndex); 121 | let fractionalPart = fixedString.substring(dotIndex + 1); 122 | 123 | while (fractionalPart.length > minimumFractionDigits && fractionalPart.endsWith('0')) { 124 | fractionalPart = fractionalPart.slice(0, -1); 125 | } 126 | 127 | if (fractionalPart) { 128 | return `${integerPart}.${fractionalPart}`; 129 | } else { 130 | return integerPart; 131 | } 132 | } 133 | 134 | function formatValue( 135 | num: number, 136 | isNegative: boolean, 137 | rule: FormatRule, 138 | minimumFractionDigits: number, 139 | maximumFractionDigits: number, 140 | roundingMode: RoundingMode 141 | ): string { 142 | const [divisor, formatInfo] = rule; 143 | const absNum = Math.abs(num); 144 | 145 | // For numbers that round up to the next tier (e.g., 999.9 -> 1K), 146 | // we need to use the scaled and rounded value, not the original number. 147 | const valueToFormat = absNum >= divisor ? absNum : num; 148 | const preScaled = preScaleNumber(Math.abs(valueToFormat), divisor, formatInfo.other[1]); 149 | const rounded = round(preScaled, maximumFractionDigits, roundingMode); 150 | 151 | const [formatString] = rounded === 1 ? formatInfo.one : formatInfo.other; 152 | const finalValue = isNegative ? -rounded : rounded; 153 | 154 | const finalValueAsString = formatNumberString( 155 | finalValue, 156 | minimumFractionDigits, 157 | maximumFractionDigits 158 | ); 159 | 160 | return polishString(formatString.replace(/0+/, finalValueAsString)); 161 | } 162 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @se-oss/compact-number 2 | 3 | [![CI](https://github.com/shahradelahi/compact-number/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](https://github.com/shahradelahi/compact-number/actions/workflows/ci.yml) 4 | [![NPM Version](https://img.shields.io/npm/v/@se-oss/compact-number.svg)](https://www.npmjs.com/package/@se-oss/compact-number) 5 | [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat)](/LICENSE) 6 | [![Install Size](https://packagephobia.com/badge?p=@se-oss/compact-number)](https://packagephobia.com/result?p=@se-oss/compact-number) 7 | 8 | _@se-oss/compact-number_ is a lightweight, fast, and highly customizable library for compact number formatting and parsing, offering robust internationalization support. 9 | 10 | --- 11 | 12 | - [Installation](#-installation) 13 | - [Usage](#-usage) 14 | - [Advanced Usage](#-advanced-usage) 15 | - [Documentation](#-documentation) 16 | - [Using Locales](#-using-locales) 17 | - [Performance](#-performance) 18 | - [Contributing](#-contributing) 19 | - [License](#license) 20 | 21 | ## 📦 Installation 22 | 23 | ```bash 24 | npm install @se-oss/compact-number 25 | ``` 26 | 27 |
28 | Install using your favorite package manager 29 | 30 | **pnpm** 31 | 32 | ```bash 33 | pnpm install @se-oss/compact-number 34 | ``` 35 | 36 | **yarn** 37 | 38 | ```bash 39 | yarn add @se-oss/compact-number 40 | ``` 41 | 42 |
43 | 44 | ## 📖 Usage 45 | 46 | ### `compactNumber` 47 | 48 | Format a number into a compact, human-readable string. 49 | 50 | ```typescript 51 | import { compactNumber } from '@se-oss/compact-number'; 52 | 53 | console.log('Formatting 1234:', compactNumber(1234)); 54 | // => 1.2K 55 | 56 | console.log('Formatting 1500000:', compactNumber(1500000)); 57 | // => 1.5M 58 | 59 | console.log( 60 | 'Formatting -1234 with precision 2:', 61 | compactNumber(-1234, { maximumFractionDigits: 2 }) 62 | ); 63 | // => -1.23K 64 | ``` 65 | 66 | ### `uncompactNumber` 67 | 68 | Parse a compacted string back into a number. 69 | 70 | ```typescript 71 | import { uncompactNumber } from '@se-oss/compact-number'; 72 | 73 | console.log(uncompactNumber('1.2K')); 74 | // => 1200 75 | 76 | console.log(uncompactNumber('1.5M')); 77 | // => 1500000 78 | 79 | console.log(uncompactNumber('-1.23K')); 80 | // => -1230 81 | ``` 82 | 83 | ## 💡 Advanced Usage 84 | 85 | You can dynamically load locales from the `cldr-numbers-full` package instead of bundling them. This is useful for applications that support many languages. 86 | 87 | First, install the CLDR data package: 88 | 89 | ```bash 90 | pnpm add cldr-numbers-full 91 | ``` 92 | 93 | ### Loading a Single Locale 94 | 95 | To keep your bundle size small, you can import and register individual locales as needed. This works in any environment. 96 | 97 | ```typescript 98 | import { compactNumber, store } from '@se-oss/compact-number'; 99 | // Import any CLDR locale data directly 100 | import ca from 'cldr-numbers-full/main/ca/numbers.json'; 101 | 102 | // Register the Catalan locale from the raw CLDR data 103 | store.registerFromCLDR(ca); 104 | 105 | // You can now format numbers using the 'ca' locale 106 | console.log(compactNumber(12345, { locale: 'ca' })); 107 | // => 12,3 mil 108 | ``` 109 | 110 | ### Loading All Locales (Node.js) 111 | 112 | In Node.js environments, you can register all available CLDR locales at once using `registerFullCLDR`. This is useful for servers that need to handle many different locales. 113 | 114 | ```typescript 115 | import { compactNumber, store } from '@se-oss/compact-number'; 116 | 117 | // Register all CLDR locales 118 | await store.registerFullCLDR(); 119 | 120 | // Now you can format numbers in any of the registered locales 121 | console.log(compactNumber(12345, { locale: 'ja' })); // Japanese 122 | // => 1.2万 123 | 124 | console.log(compactNumber(54321, { locale: 'fr' })); // French 125 | // => 54,3 k 126 | ``` 127 | 128 | **Note:** This function only works in Node.js. It will throw an error in the browser to prevent bundling the entire `cldr-numbers-full` package. 129 | 130 | ## 🌍 Using Locales 131 | 132 | By default, only the `en` locale is registered. To use other locales, you must import and register them. This ensures that unused locales are not included in your final bundle. 133 | 134 | ```typescript 135 | import { compactNumber, es, store } from '@se-oss/compact-number'; 136 | 137 | // Register the Spanish (es) locale 138 | store.register(es); 139 | 140 | console.log(compactNumber(1234, { locale: 'es' })); 141 | // => 1.2 mil 142 | ``` 143 | 144 | ## 📚 Documentation 145 | 146 | For all configuration options, please see [the API docs](https://www.jsdocs.io/package/@se-oss/compact-number). 147 | 148 | ## 🚀 Performance 149 | 150 | _@se-oss/compact-number_ is designed for speed. Our benchmarks show it's significantly faster than `Intl.NumberFormat` for compact number formatting. 151 | 152 | | Library | Operations/second (hz) | 153 | | :------------------------- | :--------------------- | 154 | | `@se-oss/compact-number` | 274,863.69 | 155 | | `Intl.NumberFormat` | 22,298.90 | 156 | | **Performance Difference** | **~12.33x faster** | 157 | 158 | _Benchmark script: [`src/index.bench.ts`](src/index.bench.ts)_ 159 | 160 | ## 🤝 Contributing 161 | 162 | Want to contribute? Awesome! To show your support is to star the project, or to raise issues on [GitHub](https://github.com/shahradelahi/compact-number) 163 | 164 | Thanks again for your support, it is much appreciated! 🙏 165 | 166 | ## License 167 | 168 | [MIT](/LICENSE) © [Shahrad Elahi](https://github.com/shahradelahi) and [contributors](https://github.com/shahradelahi/compact-number/graphs/contributors). 169 | -------------------------------------------------------------------------------- /src/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | 3 | import { parseNumberString, round, roundDecimal, toFixed } from './utils'; 4 | 5 | describe('roundDecimal', () => { 6 | test('should round down correctly', () => { 7 | expect(roundDecimal(1.234, 2)).toBe(1.23); 8 | }); 9 | 10 | test('should round up correctly', () => { 11 | expect(roundDecimal(1.236, 2)).toBe(1.24); 12 | }); 13 | 14 | test('should handle rounding .5 up', () => { 15 | expect(roundDecimal(1.5, 0)).toBe(2); 16 | expect(roundDecimal(1.25, 1)).toBe(1.3); 17 | }); 18 | 19 | test('should handle negative numbers correctly', () => { 20 | expect(roundDecimal(-1.234, 2)).toBe(-1.23); 21 | expect(roundDecimal(-1.236, 2)).toBe(-1.24); 22 | }); 23 | 24 | test('should handle negative .5 cases away from zero', () => { 25 | expect(roundDecimal(-1.5, 0)).toBe(-2); 26 | expect(roundDecimal(-1.25, 1)).toBe(-1.3); 27 | }); 28 | 29 | test('should handle high precision without floating point errors', () => { 30 | expect(roundDecimal(1.005, 2)).toBe(1.01); 31 | expect(roundDecimal(0.1 + 0.2, 10)).toBe(0.3); 32 | }); 33 | 34 | test('should handle zero', () => { 35 | expect(roundDecimal(0, 5)).toBe(0); 36 | }); 37 | }); 38 | 39 | describe('round', () => { 40 | // Test suite for 'round' mode 41 | describe('roundingMode: round', () => { 42 | test('should round down correctly', () => { 43 | expect(round(1.234, 2, 'round')).toBe(1.23); 44 | }); 45 | 46 | test('should round up correctly', () => { 47 | expect(round(1.236, 2, 'round')).toBe(1.24); 48 | }); 49 | 50 | test('should handle rounding .5 up', () => { 51 | expect(round(1.5, 0, 'round')).toBe(2); 52 | expect(round(1.25, 1, 'round')).toBe(1.3); 53 | }); 54 | 55 | test('should handle negative numbers', () => { 56 | expect(round(-1.234, 2, 'round')).toBe(-1.23); 57 | expect(round(-1.236, 2, 'round')).toBe(-1.24); 58 | expect(round(-1.5, 0, 'round')).toBe(-2); // Intl.NumberFormat rounds away from zero 59 | }); 60 | 61 | test('should handle zero precision', () => { 62 | expect(round(9.9, 0, 'round')).toBe(10); 63 | }); 64 | 65 | test('should handle zero value', () => { 66 | expect(round(0, 5, 'round')).toBe(0); 67 | }); 68 | }); 69 | 70 | // Test suite for 'floor' mode 71 | describe('roundingMode: floor', () => { 72 | test('should always round down for positive numbers', () => { 73 | expect(round(1.239, 2, 'floor')).toBe(1.23); 74 | expect(round(1.99, 0, 'floor')).toBe(1); 75 | }); 76 | 77 | test('should always round down (away from zero) for negative numbers', () => { 78 | expect(round(-1.231, 2, 'floor')).toBe(-1.24); 79 | expect(round(-1.01, 0, 'floor')).toBe(-2); 80 | }); 81 | 82 | test('should handle zero correctly', () => { 83 | expect(round(0, 2, 'floor')).toBe(0); 84 | }); 85 | }); 86 | 87 | // Test suite for 'ceil' mode 88 | describe('roundingMode: ceil', () => { 89 | test('should always round up for positive numbers', () => { 90 | expect(round(1.231, 2, 'ceil')).toBe(1.24); 91 | expect(round(1.01, 0, 'ceil')).toBe(2); 92 | }); 93 | 94 | test('should always round up (towards zero) for negative numbers', () => { 95 | expect(round(-1.239, 2, 'ceil')).toBe(-1.23); 96 | expect(round(-1.99, 0, 'ceil')).toBe(-1); 97 | }); 98 | 99 | test('should handle zero correctly', () => { 100 | expect(round(0, 2, 'ceil')).toBe(0); 101 | }); 102 | }); 103 | 104 | // Edge cases 105 | test('should handle high precision without floating point errors', () => { 106 | expect(round(0.1 + 0.2, 10, 'round')).toBe(0.3); 107 | expect(round(1.005, 2, 'round')).toBe(1.01); 108 | }); 109 | }); 110 | 111 | describe('toFixed', () => { 112 | const testCases = [ 113 | { num: 999.94, digits: 1 }, 114 | { num: 999.95, digits: 1 }, 115 | { num: 123.456, digits: 2 }, 116 | { num: 123.454, digits: 2 }, 117 | { num: 0.1 + 0.2, digits: 1 }, // Floating point 118 | { num: 1.005, digits: 2 }, 119 | { num: -999.94, digits: 1 }, 120 | { num: -999.95, digits: 1 }, 121 | { num: 123, digits: 0 }, 122 | { num: 123.0, digits: 2 }, 123 | ]; 124 | 125 | test('should produce correct results and match built-in toFixed behavior', () => { 126 | for (const { num, digits } of testCases) { 127 | const customResult = toFixed(num, digits); 128 | const builtInResult = parseFloat(num.toFixed(digits)); 129 | expect(customResult).toBeCloseTo(builtInResult); 130 | } 131 | }); 132 | }); 133 | 134 | describe('parseNumberString', () => { 135 | test('should correctly parse integer numbers', () => { 136 | expect(parseNumberString('123')).toEqual({ integerPart: '123', fractionalPart: '' }); 137 | expect(parseNumberString('-456')).toEqual({ integerPart: '-456', fractionalPart: '' }); 138 | expect(parseNumberString('0')).toEqual({ integerPart: '0', fractionalPart: '' }); 139 | }); 140 | 141 | test('should correctly parse decimal numbers', () => { 142 | expect(parseNumberString('123.456')).toEqual({ integerPart: '123', fractionalPart: '456' }); 143 | expect(parseNumberString('-123.456')).toEqual({ integerPart: '-123', fractionalPart: '456' }); 144 | expect(parseNumberString('0.123')).toEqual({ integerPart: '0', fractionalPart: '123' }); 145 | }); 146 | 147 | test('should handle numbers starting with a decimal point', () => { 148 | expect(parseNumberString('.123')).toEqual({ integerPart: '', fractionalPart: '123' }); 149 | }); 150 | 151 | test('should handle empty fractional part', () => { 152 | expect(parseNumberString('123.')).toEqual({ integerPart: '123', fractionalPart: '' }); 153 | }); 154 | 155 | test('should handle empty string', () => { 156 | expect(parseNumberString('')).toEqual({ integerPart: '', fractionalPart: '' }); 157 | }); 158 | }); 159 | -------------------------------------------------------------------------------- /src/formatter.test.ts: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, expect, test } from 'vitest'; 2 | 3 | import { compactNumber } from './formatter'; 4 | import { de, es } from './locales'; 5 | import { store } from './store'; 6 | import type { LocaleData } from './typings'; 7 | 8 | describe('compactNumber', () => { 9 | beforeEach(() => { 10 | store.reset(); 11 | // Register locales needed for tests 12 | store.register([es, de]); 13 | }); 14 | 15 | describe('Basic Formatting', () => { 16 | test('should format numbers correctly for "en" locale', () => { 17 | expect(compactNumber(1234)).toBe('1.2K'); 18 | expect(compactNumber(1500000)).toBe('1.5M'); 19 | expect(compactNumber(1000)).toBe('1K'); 20 | expect(compactNumber(1000000)).toBe('1M'); 21 | expect(compactNumber(1000000000)).toBe('1B'); 22 | expect(compactNumber(1000000000000)).toBe('1T'); 23 | }); 24 | 25 | test('should handle negative numbers', () => { 26 | expect(compactNumber(-1234)).toBe('-1.2K'); 27 | expect(compactNumber(-1500000)).toBe('-1.5M'); 28 | }); 29 | 30 | test('should handle zero and numbers less than 1000', () => { 31 | expect(compactNumber(0)).toBe('0'); 32 | expect(compactNumber(-0)).toBe('0'); 33 | expect(compactNumber(123)).toBe('123'); 34 | expect(compactNumber(-456)).toBe('-456'); 35 | expect(compactNumber(999)).toBe('999'); 36 | }); 37 | }); 38 | 39 | describe('Options', () => { 40 | test('should handle different maximumFractionDigits', () => { 41 | expect(compactNumber(1234, { maximumFractionDigits: 2 })).toBe('1.23K'); 42 | expect(compactNumber(1234, { maximumFractionDigits: 0 })).toBe('1K'); 43 | expect(compactNumber(1678, { maximumFractionDigits: 0 })).toBe('2K'); 44 | expect(compactNumber(9999, { maximumFractionDigits: 0 })).toBe('10K'); 45 | }); 46 | 47 | test('should handle different minimumFractionDigits', () => { 48 | expect(compactNumber(1200, { minimumFractionDigits: 2, maximumFractionDigits: 2 })).toBe( 49 | '1.20K' 50 | ); 51 | expect(compactNumber(1234, { minimumFractionDigits: 2, maximumFractionDigits: 2 })).toBe( 52 | '1.23K' 53 | ); 54 | expect(compactNumber(1000, { minimumFractionDigits: 2, maximumFractionDigits: 2 })).toBe( 55 | '1.00K' 56 | ); 57 | expect(compactNumber(123, { minimumFractionDigits: 2, maximumFractionDigits: 2 })).toBe( 58 | '123.00' 59 | ); 60 | }); 61 | 62 | test('should handle different styles', () => { 63 | expect(compactNumber(1234, { style: 'long' })).toBe('1.2 thousand'); 64 | expect(compactNumber(2000000, { style: 'long' })).toBe('2 million'); 65 | expect(compactNumber(1, { style: 'long' })).toBe('1'); 66 | }); 67 | 68 | test('should handle different rounding modes', () => { 69 | // Round 70 | expect(compactNumber(1290, { maximumFractionDigits: 0, roundingMode: 'round' })).toBe('1K'); 71 | expect(compactNumber(1550, { maximumFractionDigits: 1, roundingMode: 'round' })).toBe('1.6K'); 72 | expect(compactNumber(1990, { maximumFractionDigits: 0, roundingMode: 'round' })).toBe('2K'); 73 | 74 | // Floor 75 | expect(compactNumber(1290, { maximumFractionDigits: 0, roundingMode: 'floor' })).toBe('1K'); 76 | expect(compactNumber(1550, { maximumFractionDigits: 1, roundingMode: 'floor' })).toBe('1.5K'); 77 | expect(compactNumber(1990, { maximumFractionDigits: 0, roundingMode: 'floor' })).toBe('1K'); 78 | 79 | // Ceil 80 | expect(compactNumber(1290, { maximumFractionDigits: 0, roundingMode: 'ceil' })).toBe('2K'); 81 | expect(compactNumber(1550, { maximumFractionDigits: 1, roundingMode: 'ceil' })).toBe('1.6K'); 82 | expect(compactNumber(1010, { maximumFractionDigits: 0, roundingMode: 'ceil' })).toBe('2K'); 83 | }); 84 | 85 | test('should handle minimumFractionDigits for padding', () => { 86 | expect(compactNumber(1200, { maximumFractionDigits: 2, minimumFractionDigits: 2 })).toBe( 87 | '1.20K' 88 | ); 89 | expect(compactNumber(1200, { maximumFractionDigits: 2 })).toBe('1.2K'); 90 | expect(compactNumber(1000, { maximumFractionDigits: 2 })).toBe('1K'); 91 | expect(compactNumber(1234, { maximumFractionDigits: 0 })).toBe('1K'); 92 | expect(compactNumber(1234, { maximumFractionDigits: 1 })).toBe('1.2K'); 93 | expect(compactNumber(1234, { maximumFractionDigits: 2 })).toBe('1.23K'); 94 | expect(compactNumber(1230, { maximumFractionDigits: 2 })).toBe('1.23K'); 95 | expect(compactNumber(1200, { maximumFractionDigits: 0 })).toBe('1K'); 96 | expect(compactNumber(1200, { maximumFractionDigits: 1 })).toBe('1.2K'); 97 | expect(compactNumber(1200, { maximumFractionDigits: 2 })).toBe('1.2K'); 98 | }); 99 | }); 100 | 101 | describe('Locales', () => { 102 | test('should handle different built-in locales', () => { 103 | expect(compactNumber(1234, { locale: 'es' })).toBe('1.2 mil'); 104 | expect(compactNumber(1234, { locale: 'de' })).toBe('1.2 Tsd.'); 105 | }); 106 | 107 | test('should handle pluralization correctly for "es" locale', () => { 108 | expect( 109 | compactNumber(1000000, { locale: 'es', style: 'long', maximumFractionDigits: 0 }) 110 | ).toBe('1 millón'); 111 | expect(compactNumber(1500000, { locale: 'es', style: 'long' })).toBe('1.5 millones'); 112 | expect( 113 | compactNumber(2000000, { locale: 'es', style: 'long', maximumFractionDigits: 0 }) 114 | ).toBe('2 millones'); 115 | }); 116 | 117 | test('should handle custom locale data', () => { 118 | const customLocale: LocaleData = { 119 | 'fr-CA': { 120 | locale: 'fr-CA', 121 | numbers: { 122 | decimal: { 123 | long: [[1000, { one: ['0 mille', 1], other: ['0 mille', 1] }]], 124 | short: [[1000, { one: ['0k', 1], other: ['0k', 1] }]], 125 | }, 126 | }, 127 | }, 128 | }; 129 | expect(compactNumber(1234, { locale: 'fr-CA', localeData: customLocale })).toBe('1.2k'); 130 | }); 131 | 132 | test('should override existing locale data', () => { 133 | const customEn: LocaleData = { 134 | en: { 135 | locale: 'en', 136 | numbers: { 137 | decimal: { 138 | long: [[1000, { one: ['0 thousand', 1], other: ['0 thousand', 1] }]], 139 | short: [[1000, { one: ['0 Grand', 1], other: ['0 Grand', 1] }]], 140 | }, 141 | }, 142 | }, 143 | }; 144 | expect(compactNumber(1234, { locale: 'en', localeData: customEn })).toBe('1.2 Grand'); 145 | }); 146 | }); 147 | 148 | describe('Error Handling', () => { 149 | test('should throw an error for invalid input', () => { 150 | expect(() => compactNumber('invalid')).toThrow('Input must be a finite number.'); 151 | // @ts-expect-error Testing invalid input 152 | expect(() => compactNumber(undefined)).toThrow('Input must be a finite number.'); 153 | expect(() => compactNumber(NaN)).toThrow('Input must be a finite number.'); 154 | }); 155 | 156 | test('should handle null input as zero', () => { 157 | // @ts-expect-error Testing invalid input 158 | expect(compactNumber(null)).toBe('0'); 159 | }); 160 | 161 | test('should throw an error for invalid maximumFractionDigits', () => { 162 | expect(() => compactNumber(1234, { maximumFractionDigits: -1 })).toThrow( 163 | 'Fraction digits must be non-negative numbers.' 164 | ); 165 | }); 166 | 167 | test('should throw an error for invalid minimumFractionDigits', () => { 168 | expect(() => compactNumber(1234, { minimumFractionDigits: -1 })).toThrow( 169 | 'Fraction digits must be non-negative numbers.' 170 | ); 171 | }); 172 | 173 | test('should throw an error when minimumFractionDigits > maximumFractionDigits', () => { 174 | expect(() => 175 | compactNumber(1234, { minimumFractionDigits: 2, maximumFractionDigits: 1 }) 176 | ).toThrow('minimumFractionDigits cannot be greater than maximumFractionDigits.'); 177 | }); 178 | 179 | test('should throw an error for unknown locale', () => { 180 | expect(() => compactNumber(1234, { locale: 'unknown' })).toThrow( 181 | 'Locale "unknown" has not been registered. Please register it using "store.register()".' 182 | ); 183 | }); 184 | 185 | test('should throw an error for invalid rounding mode', () => { 186 | expect(() => compactNumber(1234, { roundingMode: 'invalid' as any })).toThrow( 187 | 'Invalid rounding mode: invalid' 188 | ); 189 | }); 190 | }); 191 | 192 | describe('Boundary Conditions', () => { 193 | test('should handle numbers at the threshold', () => { 194 | expect(compactNumber(1000)).toBe('1K'); 195 | expect(compactNumber(1000000)).toBe('1M'); 196 | }); 197 | 198 | test('should handle numbers just below the threshold', () => { 199 | expect(compactNumber(999)).toBe('999'); 200 | expect(compactNumber(999999)).toBe('1M'); 201 | }); 202 | 203 | test('should handle rounding that crosses a threshold', () => { 204 | expect(compactNumber(999.9, { maximumFractionDigits: 0 })).toBe('1K'); 205 | expect(compactNumber(999999, { maximumFractionDigits: 0 })).toBe('1M'); 206 | expect(compactNumber(999500, { maximumFractionDigits: 0 })).toBe('1M'); 207 | }); 208 | }); 209 | 210 | describe('Intl.NumberFormat Comparison', () => { 211 | // Helper to normalize whitespace, especially non-breaking spaces from Intl.NumberFormat 212 | const normalize = (str: string) => str.replace(/\s/g, ' '); 213 | 214 | test('should match Intl.NumberFormat for Spanish (11234)', () => { 215 | const number = 11234; 216 | const locale = 'es'; 217 | const options = { maximumFractionDigits: 0 }; 218 | const intlResult = new Intl.NumberFormat(locale, { 219 | notation: 'compact', 220 | compactDisplay: 'short', 221 | maximumFractionDigits: options.maximumFractionDigits, 222 | }).format(number); 223 | 224 | expect(normalize(compactNumber(number, { ...options, locale }))).toBe(normalize(intlResult)); 225 | }); 226 | 227 | test('should match Intl.NumberFormat for English (999999)', () => { 228 | const number = 999999; 229 | const locale = 'en'; 230 | const options = { maximumFractionDigits: 0 }; 231 | const intlResult = new Intl.NumberFormat(locale, { 232 | notation: 'compact', 233 | compactDisplay: 'short', 234 | maximumFractionDigits: options.maximumFractionDigits, 235 | }).format(number); 236 | 237 | expect(normalize(compactNumber(number, { ...options, locale }))).toBe(normalize(intlResult)); 238 | }); 239 | 240 | test('should match Intl.NumberFormat for long style', () => { 241 | const number = 12345; 242 | const locale = 'en'; 243 | const options = { 244 | maximumFractionDigits: 1, 245 | minimumFractionDigits: 1, 246 | style: 'long', 247 | } as const; 248 | const intlResult = new Intl.NumberFormat(locale, { 249 | notation: 'compact', 250 | compactDisplay: options.style, 251 | maximumFractionDigits: options.maximumFractionDigits, 252 | minimumFractionDigits: options.minimumFractionDigits, 253 | }).format(number); 254 | 255 | expect(normalize(compactNumber(number, { ...options, locale }))).toBe(normalize(intlResult)); 256 | }); 257 | 258 | test('should match Intl.NumberFormat for negative numbers', () => { 259 | const number = -5678; 260 | const locale = 'en'; 261 | const options = { maximumFractionDigits: 1 }; 262 | const intlResult = new Intl.NumberFormat(locale, { 263 | notation: 'compact', 264 | compactDisplay: 'short', 265 | maximumFractionDigits: options.maximumFractionDigits, 266 | }).format(number); 267 | 268 | expect(normalize(compactNumber(number, { ...options, locale }))).toBe(normalize(intlResult)); 269 | }); 270 | 271 | test('should match Intl.NumberFormat for higher maximumFractionDigits', () => { 272 | const number = 123456; 273 | const locale = 'en'; 274 | const options = { maximumFractionDigits: 2, minimumFractionDigits: 2 }; 275 | const intlResult = new Intl.NumberFormat(locale, { 276 | notation: 'compact', 277 | compactDisplay: 'short', 278 | maximumFractionDigits: options.maximumFractionDigits, 279 | minimumFractionDigits: options.minimumFractionDigits, 280 | }).format(number); 281 | const result = compactNumber(number, { ...options, locale }); 282 | 283 | expect(normalize(result)).toBe(normalize(intlResult)); 284 | }); 285 | }); 286 | }); 287 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@shahrad/eslint-config': 12 | specifier: ^1.0.0 13 | version: 1.0.1(jiti@2.5.1)(typescript@5.9.3) 14 | '@shahrad/prettier-config': 15 | specifier: ^1.2.2 16 | version: 1.2.2(@ianvs/prettier-plugin-sort-imports@4.5.1(prettier@3.6.2))(prettier-plugin-packagejson@2.5.18(prettier@3.6.2))(prettier-plugin-sh@0.15.0(prettier@3.6.2))(prettier@3.6.2) 17 | '@shahrad/tsconfig': 18 | specifier: ^1.2.0 19 | version: 1.2.0 20 | '@types/node': 21 | specifier: ^24.3.0 22 | version: 24.7.0 23 | cldr-numbers-full: 24 | specifier: ^47.0.0 25 | version: 47.0.0(cldr-core@47.0.0) 26 | eslint: 27 | specifier: ^9.34.0 28 | version: 9.37.0(jiti@2.5.1) 29 | globals: 30 | specifier: ^16.3.0 31 | version: 16.4.0 32 | prettier: 33 | specifier: ^3.6.2 34 | version: 3.6.2 35 | tsup: 36 | specifier: ^8.5.0 37 | version: 8.5.0(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3) 38 | tsx: 39 | specifier: ^4.20.6 40 | version: 4.20.6 41 | typescript: 42 | specifier: ^5.9.2 43 | version: 5.9.3 44 | vitest: 45 | specifier: ^3.2.4 46 | version: 3.2.4(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6) 47 | 48 | packages: 49 | 50 | '@babel/code-frame@7.27.1': 51 | resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} 52 | engines: {node: '>=6.9.0'} 53 | 54 | '@babel/generator@7.28.3': 55 | resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} 56 | engines: {node: '>=6.9.0'} 57 | 58 | '@babel/helper-globals@7.28.0': 59 | resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} 60 | engines: {node: '>=6.9.0'} 61 | 62 | '@babel/helper-string-parser@7.27.1': 63 | resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} 64 | engines: {node: '>=6.9.0'} 65 | 66 | '@babel/helper-validator-identifier@7.27.1': 67 | resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} 68 | engines: {node: '>=6.9.0'} 69 | 70 | '@babel/parser@7.28.4': 71 | resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} 72 | engines: {node: '>=6.0.0'} 73 | hasBin: true 74 | 75 | '@babel/template@7.27.2': 76 | resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} 77 | engines: {node: '>=6.9.0'} 78 | 79 | '@babel/traverse@7.28.4': 80 | resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} 81 | engines: {node: '>=6.9.0'} 82 | 83 | '@babel/types@7.28.4': 84 | resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} 85 | engines: {node: '>=6.9.0'} 86 | 87 | '@esbuild/aix-ppc64@0.25.5': 88 | resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} 89 | engines: {node: '>=18'} 90 | cpu: [ppc64] 91 | os: [aix] 92 | 93 | '@esbuild/android-arm64@0.25.5': 94 | resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} 95 | engines: {node: '>=18'} 96 | cpu: [arm64] 97 | os: [android] 98 | 99 | '@esbuild/android-arm@0.25.5': 100 | resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} 101 | engines: {node: '>=18'} 102 | cpu: [arm] 103 | os: [android] 104 | 105 | '@esbuild/android-x64@0.25.5': 106 | resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} 107 | engines: {node: '>=18'} 108 | cpu: [x64] 109 | os: [android] 110 | 111 | '@esbuild/darwin-arm64@0.25.5': 112 | resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} 113 | engines: {node: '>=18'} 114 | cpu: [arm64] 115 | os: [darwin] 116 | 117 | '@esbuild/darwin-x64@0.25.5': 118 | resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} 119 | engines: {node: '>=18'} 120 | cpu: [x64] 121 | os: [darwin] 122 | 123 | '@esbuild/freebsd-arm64@0.25.5': 124 | resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} 125 | engines: {node: '>=18'} 126 | cpu: [arm64] 127 | os: [freebsd] 128 | 129 | '@esbuild/freebsd-x64@0.25.5': 130 | resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} 131 | engines: {node: '>=18'} 132 | cpu: [x64] 133 | os: [freebsd] 134 | 135 | '@esbuild/linux-arm64@0.25.5': 136 | resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} 137 | engines: {node: '>=18'} 138 | cpu: [arm64] 139 | os: [linux] 140 | 141 | '@esbuild/linux-arm@0.25.5': 142 | resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} 143 | engines: {node: '>=18'} 144 | cpu: [arm] 145 | os: [linux] 146 | 147 | '@esbuild/linux-ia32@0.25.5': 148 | resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} 149 | engines: {node: '>=18'} 150 | cpu: [ia32] 151 | os: [linux] 152 | 153 | '@esbuild/linux-loong64@0.25.5': 154 | resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} 155 | engines: {node: '>=18'} 156 | cpu: [loong64] 157 | os: [linux] 158 | 159 | '@esbuild/linux-mips64el@0.25.5': 160 | resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} 161 | engines: {node: '>=18'} 162 | cpu: [mips64el] 163 | os: [linux] 164 | 165 | '@esbuild/linux-ppc64@0.25.5': 166 | resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} 167 | engines: {node: '>=18'} 168 | cpu: [ppc64] 169 | os: [linux] 170 | 171 | '@esbuild/linux-riscv64@0.25.5': 172 | resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} 173 | engines: {node: '>=18'} 174 | cpu: [riscv64] 175 | os: [linux] 176 | 177 | '@esbuild/linux-s390x@0.25.5': 178 | resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} 179 | engines: {node: '>=18'} 180 | cpu: [s390x] 181 | os: [linux] 182 | 183 | '@esbuild/linux-x64@0.25.5': 184 | resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} 185 | engines: {node: '>=18'} 186 | cpu: [x64] 187 | os: [linux] 188 | 189 | '@esbuild/netbsd-arm64@0.25.5': 190 | resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} 191 | engines: {node: '>=18'} 192 | cpu: [arm64] 193 | os: [netbsd] 194 | 195 | '@esbuild/netbsd-x64@0.25.5': 196 | resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} 197 | engines: {node: '>=18'} 198 | cpu: [x64] 199 | os: [netbsd] 200 | 201 | '@esbuild/openbsd-arm64@0.25.5': 202 | resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} 203 | engines: {node: '>=18'} 204 | cpu: [arm64] 205 | os: [openbsd] 206 | 207 | '@esbuild/openbsd-x64@0.25.5': 208 | resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} 209 | engines: {node: '>=18'} 210 | cpu: [x64] 211 | os: [openbsd] 212 | 213 | '@esbuild/sunos-x64@0.25.5': 214 | resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} 215 | engines: {node: '>=18'} 216 | cpu: [x64] 217 | os: [sunos] 218 | 219 | '@esbuild/win32-arm64@0.25.5': 220 | resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} 221 | engines: {node: '>=18'} 222 | cpu: [arm64] 223 | os: [win32] 224 | 225 | '@esbuild/win32-ia32@0.25.5': 226 | resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} 227 | engines: {node: '>=18'} 228 | cpu: [ia32] 229 | os: [win32] 230 | 231 | '@esbuild/win32-x64@0.25.5': 232 | resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} 233 | engines: {node: '>=18'} 234 | cpu: [x64] 235 | os: [win32] 236 | 237 | '@eslint-community/eslint-utils@4.9.0': 238 | resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} 239 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 240 | peerDependencies: 241 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 242 | 243 | '@eslint-community/regexpp@4.12.1': 244 | resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} 245 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 246 | 247 | '@eslint/config-array@0.21.0': 248 | resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} 249 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 250 | 251 | '@eslint/config-helpers@0.4.0': 252 | resolution: {integrity: sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==} 253 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 254 | 255 | '@eslint/core@0.16.0': 256 | resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} 257 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 258 | 259 | '@eslint/eslintrc@3.3.1': 260 | resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} 261 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 262 | 263 | '@eslint/js@9.37.0': 264 | resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} 265 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 266 | 267 | '@eslint/object-schema@2.1.6': 268 | resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} 269 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 270 | 271 | '@eslint/plugin-kit@0.4.0': 272 | resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} 273 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 274 | 275 | '@humanfs/core@0.19.1': 276 | resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 277 | engines: {node: '>=18.18.0'} 278 | 279 | '@humanfs/node@0.16.7': 280 | resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} 281 | engines: {node: '>=18.18.0'} 282 | 283 | '@humanwhocodes/module-importer@1.0.1': 284 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 285 | engines: {node: '>=12.22'} 286 | 287 | '@humanwhocodes/retry@0.4.3': 288 | resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} 289 | engines: {node: '>=18.18'} 290 | 291 | '@ianvs/prettier-plugin-sort-imports@4.5.1': 292 | resolution: {integrity: sha512-vOQwIyQHnHz0ikvHEQDzwUkNfX74o/7qNEpm9LiPtyBvCg/AU/DOkhwe1o92chPS1QzS6G7HeiO+OwIt8a358A==} 293 | peerDependencies: 294 | '@prettier/plugin-oxc': ^0.0.4 295 | '@vue/compiler-sfc': 2.7.x || 3.x 296 | prettier: 2 || 3 || ^4.0.0-0 297 | peerDependenciesMeta: 298 | '@prettier/plugin-oxc': 299 | optional: true 300 | '@vue/compiler-sfc': 301 | optional: true 302 | 303 | '@isaacs/cliui@8.0.2': 304 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 305 | engines: {node: '>=12'} 306 | 307 | '@jridgewell/gen-mapping@0.3.12': 308 | resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} 309 | 310 | '@jridgewell/gen-mapping@0.3.13': 311 | resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 312 | 313 | '@jridgewell/resolve-uri@3.1.2': 314 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 315 | engines: {node: '>=6.0.0'} 316 | 317 | '@jridgewell/sourcemap-codec@1.5.4': 318 | resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} 319 | 320 | '@jridgewell/sourcemap-codec@1.5.5': 321 | resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 322 | 323 | '@jridgewell/trace-mapping@0.3.29': 324 | resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} 325 | 326 | '@jridgewell/trace-mapping@0.3.31': 327 | resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 328 | 329 | '@nodelib/fs.scandir@2.1.5': 330 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 331 | engines: {node: '>= 8'} 332 | 333 | '@nodelib/fs.stat@2.0.5': 334 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 335 | engines: {node: '>= 8'} 336 | 337 | '@nodelib/fs.walk@1.2.8': 338 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 339 | engines: {node: '>= 8'} 340 | 341 | '@pkgjs/parseargs@0.11.0': 342 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 343 | engines: {node: '>=14'} 344 | 345 | '@pkgr/core@0.2.9': 346 | resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} 347 | engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} 348 | 349 | '@rollup/rollup-android-arm-eabi@4.44.2': 350 | resolution: {integrity: sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==} 351 | cpu: [arm] 352 | os: [android] 353 | 354 | '@rollup/rollup-android-arm64@4.44.2': 355 | resolution: {integrity: sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==} 356 | cpu: [arm64] 357 | os: [android] 358 | 359 | '@rollup/rollup-darwin-arm64@4.44.2': 360 | resolution: {integrity: sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==} 361 | cpu: [arm64] 362 | os: [darwin] 363 | 364 | '@rollup/rollup-darwin-x64@4.44.2': 365 | resolution: {integrity: sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==} 366 | cpu: [x64] 367 | os: [darwin] 368 | 369 | '@rollup/rollup-freebsd-arm64@4.44.2': 370 | resolution: {integrity: sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==} 371 | cpu: [arm64] 372 | os: [freebsd] 373 | 374 | '@rollup/rollup-freebsd-x64@4.44.2': 375 | resolution: {integrity: sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==} 376 | cpu: [x64] 377 | os: [freebsd] 378 | 379 | '@rollup/rollup-linux-arm-gnueabihf@4.44.2': 380 | resolution: {integrity: sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==} 381 | cpu: [arm] 382 | os: [linux] 383 | 384 | '@rollup/rollup-linux-arm-musleabihf@4.44.2': 385 | resolution: {integrity: sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==} 386 | cpu: [arm] 387 | os: [linux] 388 | 389 | '@rollup/rollup-linux-arm64-gnu@4.44.2': 390 | resolution: {integrity: sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==} 391 | cpu: [arm64] 392 | os: [linux] 393 | 394 | '@rollup/rollup-linux-arm64-musl@4.44.2': 395 | resolution: {integrity: sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==} 396 | cpu: [arm64] 397 | os: [linux] 398 | 399 | '@rollup/rollup-linux-loongarch64-gnu@4.44.2': 400 | resolution: {integrity: sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==} 401 | cpu: [loong64] 402 | os: [linux] 403 | 404 | '@rollup/rollup-linux-powerpc64le-gnu@4.44.2': 405 | resolution: {integrity: sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==} 406 | cpu: [ppc64] 407 | os: [linux] 408 | 409 | '@rollup/rollup-linux-riscv64-gnu@4.44.2': 410 | resolution: {integrity: sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==} 411 | cpu: [riscv64] 412 | os: [linux] 413 | 414 | '@rollup/rollup-linux-riscv64-musl@4.44.2': 415 | resolution: {integrity: sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==} 416 | cpu: [riscv64] 417 | os: [linux] 418 | 419 | '@rollup/rollup-linux-s390x-gnu@4.44.2': 420 | resolution: {integrity: sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==} 421 | cpu: [s390x] 422 | os: [linux] 423 | 424 | '@rollup/rollup-linux-x64-gnu@4.44.2': 425 | resolution: {integrity: sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==} 426 | cpu: [x64] 427 | os: [linux] 428 | 429 | '@rollup/rollup-linux-x64-musl@4.44.2': 430 | resolution: {integrity: sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==} 431 | cpu: [x64] 432 | os: [linux] 433 | 434 | '@rollup/rollup-win32-arm64-msvc@4.44.2': 435 | resolution: {integrity: sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==} 436 | cpu: [arm64] 437 | os: [win32] 438 | 439 | '@rollup/rollup-win32-ia32-msvc@4.44.2': 440 | resolution: {integrity: sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==} 441 | cpu: [ia32] 442 | os: [win32] 443 | 444 | '@rollup/rollup-win32-x64-msvc@4.44.2': 445 | resolution: {integrity: sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==} 446 | cpu: [x64] 447 | os: [win32] 448 | 449 | '@shahrad/eslint-config@1.0.1': 450 | resolution: {integrity: sha512-Gfjh8cdcptBjL14dWACJZ0tZy8KJdcVsOVWmyKa82v5PoLPZ4avMrT1hJyEWg0APhS1054M/udaBrlCAuHJ9XQ==} 451 | 452 | '@shahrad/prettier-config@1.2.2': 453 | resolution: {integrity: sha512-D6yRqGjD9mhdC5cWQkdoatybNmp6eZJZQ1IerFaANQL1pgtNyEasE2yFy3JdDxJRbHcL2GeaI/03tEPchU+Ddw==} 454 | peerDependencies: 455 | '@ianvs/prettier-plugin-sort-imports': ^4.4 456 | prettier: '>=3.0.0' 457 | prettier-plugin-packagejson: ^2.5 458 | prettier-plugin-sh: ^0.15 459 | 460 | '@shahrad/tsconfig@1.2.0': 461 | resolution: {integrity: sha512-5NM7tPrvUGF+VPqNgsjgWJ5aLJBcNiM/7aAsXw3PEZVek4Mfxq4vd7BLbjUsYd9HizgaNeCmfK5kIsxtCXp7/Q==} 462 | engines: {node: '>=18'} 463 | 464 | '@types/chai@5.2.2': 465 | resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} 466 | 467 | '@types/deep-eql@4.0.2': 468 | resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 469 | 470 | '@types/estree@1.0.8': 471 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 472 | 473 | '@types/json-schema@7.0.15': 474 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 475 | 476 | '@types/node@24.7.0': 477 | resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==} 478 | 479 | '@typescript-eslint/eslint-plugin@8.45.0': 480 | resolution: {integrity: sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==} 481 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 482 | peerDependencies: 483 | '@typescript-eslint/parser': ^8.45.0 484 | eslint: ^8.57.0 || ^9.0.0 485 | typescript: '>=4.8.4 <6.0.0' 486 | 487 | '@typescript-eslint/parser@8.45.0': 488 | resolution: {integrity: sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==} 489 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 490 | peerDependencies: 491 | eslint: ^8.57.0 || ^9.0.0 492 | typescript: '>=4.8.4 <6.0.0' 493 | 494 | '@typescript-eslint/project-service@8.45.0': 495 | resolution: {integrity: sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==} 496 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 497 | peerDependencies: 498 | typescript: '>=4.8.4 <6.0.0' 499 | 500 | '@typescript-eslint/scope-manager@8.45.0': 501 | resolution: {integrity: sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==} 502 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 503 | 504 | '@typescript-eslint/tsconfig-utils@8.45.0': 505 | resolution: {integrity: sha512-aFdr+c37sc+jqNMGhH+ajxPXwjv9UtFZk79k8pLoJ6p4y0snmYpPA52GuWHgt2ZF4gRRW6odsEj41uZLojDt5w==} 506 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 507 | peerDependencies: 508 | typescript: '>=4.8.4 <6.0.0' 509 | 510 | '@typescript-eslint/type-utils@8.45.0': 511 | resolution: {integrity: sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==} 512 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 513 | peerDependencies: 514 | eslint: ^8.57.0 || ^9.0.0 515 | typescript: '>=4.8.4 <6.0.0' 516 | 517 | '@typescript-eslint/types@8.45.0': 518 | resolution: {integrity: sha512-WugXLuOIq67BMgQInIxxnsSyRLFxdkJEJu8r4ngLR56q/4Q5LrbfkFRH27vMTjxEK8Pyz7QfzuZe/G15qQnVRA==} 519 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 520 | 521 | '@typescript-eslint/typescript-estree@8.45.0': 522 | resolution: {integrity: sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==} 523 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 524 | peerDependencies: 525 | typescript: '>=4.8.4 <6.0.0' 526 | 527 | '@typescript-eslint/utils@8.45.0': 528 | resolution: {integrity: sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==} 529 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 530 | peerDependencies: 531 | eslint: ^8.57.0 || ^9.0.0 532 | typescript: '>=4.8.4 <6.0.0' 533 | 534 | '@typescript-eslint/visitor-keys@8.45.0': 535 | resolution: {integrity: sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==} 536 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 537 | 538 | '@vitest/expect@3.2.4': 539 | resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} 540 | 541 | '@vitest/mocker@3.2.4': 542 | resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} 543 | peerDependencies: 544 | msw: ^2.4.9 545 | vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 546 | peerDependenciesMeta: 547 | msw: 548 | optional: true 549 | vite: 550 | optional: true 551 | 552 | '@vitest/pretty-format@3.2.4': 553 | resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} 554 | 555 | '@vitest/runner@3.2.4': 556 | resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} 557 | 558 | '@vitest/snapshot@3.2.4': 559 | resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} 560 | 561 | '@vitest/spy@3.2.4': 562 | resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} 563 | 564 | '@vitest/utils@3.2.4': 565 | resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} 566 | 567 | acorn-jsx@5.3.2: 568 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 569 | peerDependencies: 570 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 571 | 572 | acorn@8.15.0: 573 | resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 574 | engines: {node: '>=0.4.0'} 575 | hasBin: true 576 | 577 | ajv@6.12.6: 578 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 579 | 580 | ansi-regex@5.0.1: 581 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 582 | engines: {node: '>=8'} 583 | 584 | ansi-regex@6.1.0: 585 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 586 | engines: {node: '>=12'} 587 | 588 | ansi-styles@4.3.0: 589 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 590 | engines: {node: '>=8'} 591 | 592 | ansi-styles@6.2.3: 593 | resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} 594 | engines: {node: '>=12'} 595 | 596 | any-promise@1.3.0: 597 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 598 | 599 | argparse@2.0.1: 600 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 601 | 602 | assertion-error@2.0.1: 603 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 604 | engines: {node: '>=12'} 605 | 606 | balanced-match@1.0.2: 607 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 608 | 609 | brace-expansion@1.1.12: 610 | resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} 611 | 612 | brace-expansion@2.0.2: 613 | resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} 614 | 615 | braces@3.0.3: 616 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 617 | engines: {node: '>=8'} 618 | 619 | bundle-require@5.1.0: 620 | resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} 621 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 622 | peerDependencies: 623 | esbuild: '>=0.18' 624 | 625 | cac@6.7.14: 626 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 627 | engines: {node: '>=8'} 628 | 629 | callsites@3.1.0: 630 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 631 | engines: {node: '>=6'} 632 | 633 | chai@5.2.1: 634 | resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==} 635 | engines: {node: '>=18'} 636 | 637 | chalk@4.1.2: 638 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 639 | engines: {node: '>=10'} 640 | 641 | check-error@2.1.1: 642 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 643 | engines: {node: '>= 16'} 644 | 645 | chokidar@4.0.3: 646 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 647 | engines: {node: '>= 14.16.0'} 648 | 649 | cldr-core@47.0.0: 650 | resolution: {integrity: sha512-tdYRy66DMgpjEwVOWCTN0zhNr+zh1+d4A6MCNgJKU7voFDGsrwcWHor6jcqudHDmElCgyVNqWBKAB1JeNdSOKg==} 651 | 652 | cldr-numbers-full@47.0.0: 653 | resolution: {integrity: sha512-5OXUfjiAdXYuVD4XlaQe++WKBVmI1bkKxO0uWJMpbokzgcJ30vhFzcX5WsnZMtoZuhEpOt5KubCJaxaHPj5XTQ==} 654 | peerDependencies: 655 | cldr-core: 47.0.0 656 | 657 | color-convert@2.0.1: 658 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 659 | engines: {node: '>=7.0.0'} 660 | 661 | color-name@1.1.4: 662 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 663 | 664 | commander@4.1.1: 665 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 666 | engines: {node: '>= 6'} 667 | 668 | concat-map@0.0.1: 669 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 670 | 671 | confbox@0.1.8: 672 | resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} 673 | 674 | consola@3.4.2: 675 | resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} 676 | engines: {node: ^14.18.0 || >=16.10.0} 677 | 678 | cross-spawn@7.0.6: 679 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 680 | engines: {node: '>= 8'} 681 | 682 | debug@4.4.1: 683 | resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} 684 | engines: {node: '>=6.0'} 685 | peerDependencies: 686 | supports-color: '*' 687 | peerDependenciesMeta: 688 | supports-color: 689 | optional: true 690 | 691 | debug@4.4.3: 692 | resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 693 | engines: {node: '>=6.0'} 694 | peerDependencies: 695 | supports-color: '*' 696 | peerDependenciesMeta: 697 | supports-color: 698 | optional: true 699 | 700 | deep-eql@5.0.2: 701 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 702 | engines: {node: '>=6'} 703 | 704 | deep-is@0.1.4: 705 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 706 | 707 | detect-indent@7.0.2: 708 | resolution: {integrity: sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==} 709 | engines: {node: '>=12.20'} 710 | 711 | detect-newline@4.0.1: 712 | resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} 713 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 714 | 715 | eastasianwidth@0.2.0: 716 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 717 | 718 | emoji-regex@8.0.0: 719 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 720 | 721 | emoji-regex@9.2.2: 722 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 723 | 724 | es-module-lexer@1.7.0: 725 | resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} 726 | 727 | esbuild@0.25.5: 728 | resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} 729 | engines: {node: '>=18'} 730 | hasBin: true 731 | 732 | escape-string-regexp@4.0.0: 733 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 734 | engines: {node: '>=10'} 735 | 736 | eslint-scope@8.4.0: 737 | resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} 738 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 739 | 740 | eslint-visitor-keys@3.4.3: 741 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 742 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 743 | 744 | eslint-visitor-keys@4.2.1: 745 | resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} 746 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 747 | 748 | eslint@9.37.0: 749 | resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} 750 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 751 | hasBin: true 752 | peerDependencies: 753 | jiti: '*' 754 | peerDependenciesMeta: 755 | jiti: 756 | optional: true 757 | 758 | espree@10.4.0: 759 | resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} 760 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 761 | 762 | esquery@1.6.0: 763 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 764 | engines: {node: '>=0.10'} 765 | 766 | esrecurse@4.3.0: 767 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 768 | engines: {node: '>=4.0'} 769 | 770 | estraverse@5.3.0: 771 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 772 | engines: {node: '>=4.0'} 773 | 774 | estree-walker@3.0.3: 775 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 776 | 777 | esutils@2.0.3: 778 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 779 | engines: {node: '>=0.10.0'} 780 | 781 | expect-type@1.2.1: 782 | resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} 783 | engines: {node: '>=12.0.0'} 784 | 785 | fast-deep-equal@3.1.3: 786 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 787 | 788 | fast-glob@3.3.3: 789 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 790 | engines: {node: '>=8.6.0'} 791 | 792 | fast-json-stable-stringify@2.1.0: 793 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 794 | 795 | fast-levenshtein@2.0.6: 796 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 797 | 798 | fastq@1.19.1: 799 | resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} 800 | 801 | fdir@6.4.6: 802 | resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} 803 | peerDependencies: 804 | picomatch: ^3 || ^4 805 | peerDependenciesMeta: 806 | picomatch: 807 | optional: true 808 | 809 | fdir@6.5.0: 810 | resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 811 | engines: {node: '>=12.0.0'} 812 | peerDependencies: 813 | picomatch: ^3 || ^4 814 | peerDependenciesMeta: 815 | picomatch: 816 | optional: true 817 | 818 | file-entry-cache@8.0.0: 819 | resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 820 | engines: {node: '>=16.0.0'} 821 | 822 | fill-range@7.1.1: 823 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 824 | engines: {node: '>=8'} 825 | 826 | find-up@5.0.0: 827 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 828 | engines: {node: '>=10'} 829 | 830 | fix-dts-default-cjs-exports@1.0.1: 831 | resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} 832 | 833 | flat-cache@4.0.1: 834 | resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} 835 | engines: {node: '>=16'} 836 | 837 | flatted@3.3.3: 838 | resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 839 | 840 | foreground-child@3.3.1: 841 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 842 | engines: {node: '>=14'} 843 | 844 | fsevents@2.3.3: 845 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 846 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 847 | os: [darwin] 848 | 849 | get-tsconfig@4.10.1: 850 | resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} 851 | 852 | git-hooks-list@4.1.1: 853 | resolution: {integrity: sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==} 854 | 855 | glob-parent@5.1.2: 856 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 857 | engines: {node: '>= 6'} 858 | 859 | glob-parent@6.0.2: 860 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 861 | engines: {node: '>=10.13.0'} 862 | 863 | glob@10.4.5: 864 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 865 | hasBin: true 866 | 867 | globals@14.0.0: 868 | resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} 869 | engines: {node: '>=18'} 870 | 871 | globals@16.4.0: 872 | resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} 873 | engines: {node: '>=18'} 874 | 875 | graphemer@1.4.0: 876 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 877 | 878 | has-flag@4.0.0: 879 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 880 | engines: {node: '>=8'} 881 | 882 | ignore@5.3.2: 883 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 884 | engines: {node: '>= 4'} 885 | 886 | ignore@7.0.5: 887 | resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} 888 | engines: {node: '>= 4'} 889 | 890 | import-fresh@3.3.1: 891 | resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} 892 | engines: {node: '>=6'} 893 | 894 | imurmurhash@0.1.4: 895 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 896 | engines: {node: '>=0.8.19'} 897 | 898 | is-extglob@2.1.1: 899 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 900 | engines: {node: '>=0.10.0'} 901 | 902 | is-fullwidth-code-point@3.0.0: 903 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 904 | engines: {node: '>=8'} 905 | 906 | is-glob@4.0.3: 907 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 908 | engines: {node: '>=0.10.0'} 909 | 910 | is-number@7.0.0: 911 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 912 | engines: {node: '>=0.12.0'} 913 | 914 | is-plain-obj@4.1.0: 915 | resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} 916 | engines: {node: '>=12'} 917 | 918 | isexe@2.0.0: 919 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 920 | 921 | jackspeak@3.4.3: 922 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 923 | 924 | jiti@2.5.1: 925 | resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} 926 | hasBin: true 927 | 928 | joycon@3.1.1: 929 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 930 | engines: {node: '>=10'} 931 | 932 | js-tokens@4.0.0: 933 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 934 | 935 | js-tokens@9.0.1: 936 | resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} 937 | 938 | js-yaml@4.1.0: 939 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 940 | hasBin: true 941 | 942 | jsesc@3.1.0: 943 | resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} 944 | engines: {node: '>=6'} 945 | hasBin: true 946 | 947 | json-buffer@3.0.1: 948 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 949 | 950 | json-schema-traverse@0.4.1: 951 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 952 | 953 | json-stable-stringify-without-jsonify@1.0.1: 954 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 955 | 956 | keyv@4.5.4: 957 | resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} 958 | 959 | levn@0.4.1: 960 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 961 | engines: {node: '>= 0.8.0'} 962 | 963 | lilconfig@3.1.3: 964 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 965 | engines: {node: '>=14'} 966 | 967 | lines-and-columns@1.2.4: 968 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 969 | 970 | load-tsconfig@0.2.5: 971 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 972 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 973 | 974 | locate-path@6.0.0: 975 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 976 | engines: {node: '>=10'} 977 | 978 | lodash.merge@4.6.2: 979 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 980 | 981 | lodash.sortby@4.7.0: 982 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 983 | 984 | loupe@3.1.4: 985 | resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} 986 | 987 | lru-cache@10.4.3: 988 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 989 | 990 | magic-string@0.30.17: 991 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 992 | 993 | merge2@1.4.1: 994 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 995 | engines: {node: '>= 8'} 996 | 997 | micromatch@4.0.8: 998 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 999 | engines: {node: '>=8.6'} 1000 | 1001 | minimatch@3.1.2: 1002 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1003 | 1004 | minimatch@9.0.5: 1005 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1006 | engines: {node: '>=16 || 14 >=14.17'} 1007 | 1008 | minipass@7.1.2: 1009 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 1010 | engines: {node: '>=16 || 14 >=14.17'} 1011 | 1012 | mlly@1.7.4: 1013 | resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} 1014 | 1015 | ms@2.1.3: 1016 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1017 | 1018 | mvdan-sh@0.10.1: 1019 | resolution: {integrity: sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg==} 1020 | deprecated: See https://github.com/mvdan/sh/issues/1145 1021 | 1022 | mz@2.7.0: 1023 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 1024 | 1025 | nanoid@3.3.11: 1026 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 1027 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1028 | hasBin: true 1029 | 1030 | natural-compare@1.4.0: 1031 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1032 | 1033 | object-assign@4.1.1: 1034 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1035 | engines: {node: '>=0.10.0'} 1036 | 1037 | optionator@0.9.4: 1038 | resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1039 | engines: {node: '>= 0.8.0'} 1040 | 1041 | p-limit@3.1.0: 1042 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1043 | engines: {node: '>=10'} 1044 | 1045 | p-locate@5.0.0: 1046 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1047 | engines: {node: '>=10'} 1048 | 1049 | package-json-from-dist@1.0.1: 1050 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 1051 | 1052 | parent-module@1.0.1: 1053 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1054 | engines: {node: '>=6'} 1055 | 1056 | path-exists@4.0.0: 1057 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1058 | engines: {node: '>=8'} 1059 | 1060 | path-key@3.1.1: 1061 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1062 | engines: {node: '>=8'} 1063 | 1064 | path-scurry@1.11.1: 1065 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 1066 | engines: {node: '>=16 || 14 >=14.18'} 1067 | 1068 | pathe@2.0.3: 1069 | resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 1070 | 1071 | pathval@2.0.1: 1072 | resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} 1073 | engines: {node: '>= 14.16'} 1074 | 1075 | picocolors@1.1.1: 1076 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1077 | 1078 | picomatch@2.3.1: 1079 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1080 | engines: {node: '>=8.6'} 1081 | 1082 | picomatch@4.0.2: 1083 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 1084 | engines: {node: '>=12'} 1085 | 1086 | picomatch@4.0.3: 1087 | resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 1088 | engines: {node: '>=12'} 1089 | 1090 | pirates@4.0.7: 1091 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 1092 | engines: {node: '>= 6'} 1093 | 1094 | pkg-types@1.3.1: 1095 | resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} 1096 | 1097 | postcss-load-config@6.0.1: 1098 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} 1099 | engines: {node: '>= 18'} 1100 | peerDependencies: 1101 | jiti: '>=1.21.0' 1102 | postcss: '>=8.0.9' 1103 | tsx: ^4.8.1 1104 | yaml: ^2.4.2 1105 | peerDependenciesMeta: 1106 | jiti: 1107 | optional: true 1108 | postcss: 1109 | optional: true 1110 | tsx: 1111 | optional: true 1112 | yaml: 1113 | optional: true 1114 | 1115 | postcss@8.5.6: 1116 | resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 1117 | engines: {node: ^10 || ^12 || >=14} 1118 | 1119 | prelude-ls@1.2.1: 1120 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1121 | engines: {node: '>= 0.8.0'} 1122 | 1123 | prettier-plugin-packagejson@2.5.18: 1124 | resolution: {integrity: sha512-NKznPGcGrcj4NPGxnh+w78JXPyfB6I4RQSCM0v+CAXwpDG7OEpJQ5zMyfC5NBgKH1k7Skwcj5ak5by2mrHvC5g==} 1125 | peerDependencies: 1126 | prettier: '>= 1.16.0' 1127 | peerDependenciesMeta: 1128 | prettier: 1129 | optional: true 1130 | 1131 | prettier-plugin-sh@0.15.0: 1132 | resolution: {integrity: sha512-U0PikJr/yr2bzzARl43qI0mApBj0C1xdAfA04AZa6LnvIKawXHhuy2fFo6LNA7weRzGlAiNbaEFfKMFo0nZr/A==} 1133 | engines: {node: '>=16.0.0'} 1134 | peerDependencies: 1135 | prettier: ^3.0.3 1136 | 1137 | prettier@3.6.2: 1138 | resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} 1139 | engines: {node: '>=14'} 1140 | hasBin: true 1141 | 1142 | punycode@2.3.1: 1143 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1144 | engines: {node: '>=6'} 1145 | 1146 | queue-microtask@1.2.3: 1147 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1148 | 1149 | readdirp@4.1.2: 1150 | resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 1151 | engines: {node: '>= 14.18.0'} 1152 | 1153 | resolve-from@4.0.0: 1154 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1155 | engines: {node: '>=4'} 1156 | 1157 | resolve-from@5.0.0: 1158 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1159 | engines: {node: '>=8'} 1160 | 1161 | resolve-pkg-maps@1.0.0: 1162 | resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} 1163 | 1164 | reusify@1.1.0: 1165 | resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 1166 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1167 | 1168 | rollup@4.44.2: 1169 | resolution: {integrity: sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==} 1170 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1171 | hasBin: true 1172 | 1173 | run-parallel@1.2.0: 1174 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1175 | 1176 | semver@7.7.2: 1177 | resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} 1178 | engines: {node: '>=10'} 1179 | hasBin: true 1180 | 1181 | sh-syntax@0.4.2: 1182 | resolution: {integrity: sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg==} 1183 | engines: {node: '>=16.0.0'} 1184 | 1185 | shebang-command@2.0.0: 1186 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1187 | engines: {node: '>=8'} 1188 | 1189 | shebang-regex@3.0.0: 1190 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1191 | engines: {node: '>=8'} 1192 | 1193 | siginfo@2.0.0: 1194 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1195 | 1196 | signal-exit@4.1.0: 1197 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1198 | engines: {node: '>=14'} 1199 | 1200 | sort-object-keys@1.1.3: 1201 | resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} 1202 | 1203 | sort-package-json@3.4.0: 1204 | resolution: {integrity: sha512-97oFRRMM2/Js4oEA9LJhjyMlde+2ewpZQf53pgue27UkbEXfHJnDzHlUxQ/DWUkzqmp7DFwJp8D+wi/TYeQhpA==} 1205 | engines: {node: '>=20'} 1206 | hasBin: true 1207 | 1208 | source-map-js@1.2.1: 1209 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1210 | engines: {node: '>=0.10.0'} 1211 | 1212 | source-map@0.8.0-beta.0: 1213 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 1214 | engines: {node: '>= 8'} 1215 | deprecated: The work that was done in this beta branch won't be included in future versions 1216 | 1217 | stackback@0.0.2: 1218 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1219 | 1220 | std-env@3.9.0: 1221 | resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} 1222 | 1223 | string-width@4.2.3: 1224 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1225 | engines: {node: '>=8'} 1226 | 1227 | string-width@5.1.2: 1228 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1229 | engines: {node: '>=12'} 1230 | 1231 | strip-ansi@6.0.1: 1232 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1233 | engines: {node: '>=8'} 1234 | 1235 | strip-ansi@7.1.0: 1236 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1237 | engines: {node: '>=12'} 1238 | 1239 | strip-json-comments@3.1.1: 1240 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 1241 | engines: {node: '>=8'} 1242 | 1243 | strip-literal@3.0.0: 1244 | resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} 1245 | 1246 | sucrase@3.35.0: 1247 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1248 | engines: {node: '>=16 || 14 >=14.17'} 1249 | hasBin: true 1250 | 1251 | supports-color@7.2.0: 1252 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1253 | engines: {node: '>=8'} 1254 | 1255 | synckit@0.11.8: 1256 | resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} 1257 | engines: {node: ^14.18.0 || >=16.0.0} 1258 | 1259 | thenify-all@1.6.0: 1260 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1261 | engines: {node: '>=0.8'} 1262 | 1263 | thenify@3.3.1: 1264 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1265 | 1266 | tinybench@2.9.0: 1267 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1268 | 1269 | tinyexec@0.3.2: 1270 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 1271 | 1272 | tinyglobby@0.2.14: 1273 | resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} 1274 | engines: {node: '>=12.0.0'} 1275 | 1276 | tinyglobby@0.2.15: 1277 | resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 1278 | engines: {node: '>=12.0.0'} 1279 | 1280 | tinypool@1.1.1: 1281 | resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} 1282 | engines: {node: ^18.0.0 || >=20.0.0} 1283 | 1284 | tinyrainbow@2.0.0: 1285 | resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} 1286 | engines: {node: '>=14.0.0'} 1287 | 1288 | tinyspy@4.0.3: 1289 | resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} 1290 | engines: {node: '>=14.0.0'} 1291 | 1292 | to-regex-range@5.0.1: 1293 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1294 | engines: {node: '>=8.0'} 1295 | 1296 | tr46@1.0.1: 1297 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 1298 | 1299 | tree-kill@1.2.2: 1300 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1301 | hasBin: true 1302 | 1303 | ts-api-utils@2.1.0: 1304 | resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} 1305 | engines: {node: '>=18.12'} 1306 | peerDependencies: 1307 | typescript: '>=4.8.4' 1308 | 1309 | ts-interface-checker@0.1.13: 1310 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1311 | 1312 | tslib@2.8.1: 1313 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1314 | 1315 | tsup@8.5.0: 1316 | resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} 1317 | engines: {node: '>=18'} 1318 | hasBin: true 1319 | peerDependencies: 1320 | '@microsoft/api-extractor': ^7.36.0 1321 | '@swc/core': ^1 1322 | postcss: ^8.4.12 1323 | typescript: '>=4.5.0' 1324 | peerDependenciesMeta: 1325 | '@microsoft/api-extractor': 1326 | optional: true 1327 | '@swc/core': 1328 | optional: true 1329 | postcss: 1330 | optional: true 1331 | typescript: 1332 | optional: true 1333 | 1334 | tsx@4.20.6: 1335 | resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} 1336 | engines: {node: '>=18.0.0'} 1337 | hasBin: true 1338 | 1339 | type-check@0.4.0: 1340 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 1341 | engines: {node: '>= 0.8.0'} 1342 | 1343 | typescript-eslint@8.45.0: 1344 | resolution: {integrity: sha512-qzDmZw/Z5beNLUrXfd0HIW6MzIaAV5WNDxmMs9/3ojGOpYavofgNAAD/nC6tGV2PczIi0iw8vot2eAe/sBn7zg==} 1345 | engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 1346 | peerDependencies: 1347 | eslint: ^8.57.0 || ^9.0.0 1348 | typescript: '>=4.8.4 <6.0.0' 1349 | 1350 | typescript@5.9.3: 1351 | resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 1352 | engines: {node: '>=14.17'} 1353 | hasBin: true 1354 | 1355 | ufo@1.6.1: 1356 | resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} 1357 | 1358 | undici-types@7.14.0: 1359 | resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} 1360 | 1361 | uri-js@4.4.1: 1362 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 1363 | 1364 | vite-node@3.2.4: 1365 | resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} 1366 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1367 | hasBin: true 1368 | 1369 | vite@7.0.2: 1370 | resolution: {integrity: sha512-hxdyZDY1CM6SNpKI4w4lcUc3Mtkd9ej4ECWVHSMrOdSinVc2zYOAppHeGc/hzmRo3pxM5blMzkuWHOJA/3NiFw==} 1371 | engines: {node: ^20.19.0 || >=22.12.0} 1372 | hasBin: true 1373 | peerDependencies: 1374 | '@types/node': ^20.19.0 || >=22.12.0 1375 | jiti: '>=1.21.0' 1376 | less: ^4.0.0 1377 | lightningcss: ^1.21.0 1378 | sass: ^1.70.0 1379 | sass-embedded: ^1.70.0 1380 | stylus: '>=0.54.8' 1381 | sugarss: ^5.0.0 1382 | terser: ^5.16.0 1383 | tsx: ^4.8.1 1384 | yaml: ^2.4.2 1385 | peerDependenciesMeta: 1386 | '@types/node': 1387 | optional: true 1388 | jiti: 1389 | optional: true 1390 | less: 1391 | optional: true 1392 | lightningcss: 1393 | optional: true 1394 | sass: 1395 | optional: true 1396 | sass-embedded: 1397 | optional: true 1398 | stylus: 1399 | optional: true 1400 | sugarss: 1401 | optional: true 1402 | terser: 1403 | optional: true 1404 | tsx: 1405 | optional: true 1406 | yaml: 1407 | optional: true 1408 | 1409 | vitest@3.2.4: 1410 | resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} 1411 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1412 | hasBin: true 1413 | peerDependencies: 1414 | '@edge-runtime/vm': '*' 1415 | '@types/debug': ^4.1.12 1416 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 1417 | '@vitest/browser': 3.2.4 1418 | '@vitest/ui': 3.2.4 1419 | happy-dom: '*' 1420 | jsdom: '*' 1421 | peerDependenciesMeta: 1422 | '@edge-runtime/vm': 1423 | optional: true 1424 | '@types/debug': 1425 | optional: true 1426 | '@types/node': 1427 | optional: true 1428 | '@vitest/browser': 1429 | optional: true 1430 | '@vitest/ui': 1431 | optional: true 1432 | happy-dom: 1433 | optional: true 1434 | jsdom: 1435 | optional: true 1436 | 1437 | webidl-conversions@4.0.2: 1438 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 1439 | 1440 | whatwg-url@7.1.0: 1441 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 1442 | 1443 | which@2.0.2: 1444 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1445 | engines: {node: '>= 8'} 1446 | hasBin: true 1447 | 1448 | why-is-node-running@2.3.0: 1449 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1450 | engines: {node: '>=8'} 1451 | hasBin: true 1452 | 1453 | word-wrap@1.2.5: 1454 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 1455 | engines: {node: '>=0.10.0'} 1456 | 1457 | wrap-ansi@7.0.0: 1458 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1459 | engines: {node: '>=10'} 1460 | 1461 | wrap-ansi@8.1.0: 1462 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1463 | engines: {node: '>=12'} 1464 | 1465 | yocto-queue@0.1.0: 1466 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1467 | engines: {node: '>=10'} 1468 | 1469 | snapshots: 1470 | 1471 | '@babel/code-frame@7.27.1': 1472 | dependencies: 1473 | '@babel/helper-validator-identifier': 7.27.1 1474 | js-tokens: 4.0.0 1475 | picocolors: 1.1.1 1476 | 1477 | '@babel/generator@7.28.3': 1478 | dependencies: 1479 | '@babel/parser': 7.28.4 1480 | '@babel/types': 7.28.4 1481 | '@jridgewell/gen-mapping': 0.3.13 1482 | '@jridgewell/trace-mapping': 0.3.31 1483 | jsesc: 3.1.0 1484 | 1485 | '@babel/helper-globals@7.28.0': {} 1486 | 1487 | '@babel/helper-string-parser@7.27.1': {} 1488 | 1489 | '@babel/helper-validator-identifier@7.27.1': {} 1490 | 1491 | '@babel/parser@7.28.4': 1492 | dependencies: 1493 | '@babel/types': 7.28.4 1494 | 1495 | '@babel/template@7.27.2': 1496 | dependencies: 1497 | '@babel/code-frame': 7.27.1 1498 | '@babel/parser': 7.28.4 1499 | '@babel/types': 7.28.4 1500 | 1501 | '@babel/traverse@7.28.4': 1502 | dependencies: 1503 | '@babel/code-frame': 7.27.1 1504 | '@babel/generator': 7.28.3 1505 | '@babel/helper-globals': 7.28.0 1506 | '@babel/parser': 7.28.4 1507 | '@babel/template': 7.27.2 1508 | '@babel/types': 7.28.4 1509 | debug: 4.4.3 1510 | transitivePeerDependencies: 1511 | - supports-color 1512 | 1513 | '@babel/types@7.28.4': 1514 | dependencies: 1515 | '@babel/helper-string-parser': 7.27.1 1516 | '@babel/helper-validator-identifier': 7.27.1 1517 | 1518 | '@esbuild/aix-ppc64@0.25.5': 1519 | optional: true 1520 | 1521 | '@esbuild/android-arm64@0.25.5': 1522 | optional: true 1523 | 1524 | '@esbuild/android-arm@0.25.5': 1525 | optional: true 1526 | 1527 | '@esbuild/android-x64@0.25.5': 1528 | optional: true 1529 | 1530 | '@esbuild/darwin-arm64@0.25.5': 1531 | optional: true 1532 | 1533 | '@esbuild/darwin-x64@0.25.5': 1534 | optional: true 1535 | 1536 | '@esbuild/freebsd-arm64@0.25.5': 1537 | optional: true 1538 | 1539 | '@esbuild/freebsd-x64@0.25.5': 1540 | optional: true 1541 | 1542 | '@esbuild/linux-arm64@0.25.5': 1543 | optional: true 1544 | 1545 | '@esbuild/linux-arm@0.25.5': 1546 | optional: true 1547 | 1548 | '@esbuild/linux-ia32@0.25.5': 1549 | optional: true 1550 | 1551 | '@esbuild/linux-loong64@0.25.5': 1552 | optional: true 1553 | 1554 | '@esbuild/linux-mips64el@0.25.5': 1555 | optional: true 1556 | 1557 | '@esbuild/linux-ppc64@0.25.5': 1558 | optional: true 1559 | 1560 | '@esbuild/linux-riscv64@0.25.5': 1561 | optional: true 1562 | 1563 | '@esbuild/linux-s390x@0.25.5': 1564 | optional: true 1565 | 1566 | '@esbuild/linux-x64@0.25.5': 1567 | optional: true 1568 | 1569 | '@esbuild/netbsd-arm64@0.25.5': 1570 | optional: true 1571 | 1572 | '@esbuild/netbsd-x64@0.25.5': 1573 | optional: true 1574 | 1575 | '@esbuild/openbsd-arm64@0.25.5': 1576 | optional: true 1577 | 1578 | '@esbuild/openbsd-x64@0.25.5': 1579 | optional: true 1580 | 1581 | '@esbuild/sunos-x64@0.25.5': 1582 | optional: true 1583 | 1584 | '@esbuild/win32-arm64@0.25.5': 1585 | optional: true 1586 | 1587 | '@esbuild/win32-ia32@0.25.5': 1588 | optional: true 1589 | 1590 | '@esbuild/win32-x64@0.25.5': 1591 | optional: true 1592 | 1593 | '@eslint-community/eslint-utils@4.9.0(eslint@9.37.0(jiti@2.5.1))': 1594 | dependencies: 1595 | eslint: 9.37.0(jiti@2.5.1) 1596 | eslint-visitor-keys: 3.4.3 1597 | 1598 | '@eslint-community/regexpp@4.12.1': {} 1599 | 1600 | '@eslint/config-array@0.21.0': 1601 | dependencies: 1602 | '@eslint/object-schema': 2.1.6 1603 | debug: 4.4.3 1604 | minimatch: 3.1.2 1605 | transitivePeerDependencies: 1606 | - supports-color 1607 | 1608 | '@eslint/config-helpers@0.4.0': 1609 | dependencies: 1610 | '@eslint/core': 0.16.0 1611 | 1612 | '@eslint/core@0.16.0': 1613 | dependencies: 1614 | '@types/json-schema': 7.0.15 1615 | 1616 | '@eslint/eslintrc@3.3.1': 1617 | dependencies: 1618 | ajv: 6.12.6 1619 | debug: 4.4.3 1620 | espree: 10.4.0 1621 | globals: 14.0.0 1622 | ignore: 5.3.2 1623 | import-fresh: 3.3.1 1624 | js-yaml: 4.1.0 1625 | minimatch: 3.1.2 1626 | strip-json-comments: 3.1.1 1627 | transitivePeerDependencies: 1628 | - supports-color 1629 | 1630 | '@eslint/js@9.37.0': {} 1631 | 1632 | '@eslint/object-schema@2.1.6': {} 1633 | 1634 | '@eslint/plugin-kit@0.4.0': 1635 | dependencies: 1636 | '@eslint/core': 0.16.0 1637 | levn: 0.4.1 1638 | 1639 | '@humanfs/core@0.19.1': {} 1640 | 1641 | '@humanfs/node@0.16.7': 1642 | dependencies: 1643 | '@humanfs/core': 0.19.1 1644 | '@humanwhocodes/retry': 0.4.3 1645 | 1646 | '@humanwhocodes/module-importer@1.0.1': {} 1647 | 1648 | '@humanwhocodes/retry@0.4.3': {} 1649 | 1650 | '@ianvs/prettier-plugin-sort-imports@4.5.1(prettier@3.6.2)': 1651 | dependencies: 1652 | '@babel/generator': 7.28.3 1653 | '@babel/parser': 7.28.4 1654 | '@babel/traverse': 7.28.4 1655 | '@babel/types': 7.28.4 1656 | prettier: 3.6.2 1657 | semver: 7.7.2 1658 | transitivePeerDependencies: 1659 | - supports-color 1660 | 1661 | '@isaacs/cliui@8.0.2': 1662 | dependencies: 1663 | string-width: 5.1.2 1664 | string-width-cjs: string-width@4.2.3 1665 | strip-ansi: 7.1.0 1666 | strip-ansi-cjs: strip-ansi@6.0.1 1667 | wrap-ansi: 8.1.0 1668 | wrap-ansi-cjs: wrap-ansi@7.0.0 1669 | 1670 | '@jridgewell/gen-mapping@0.3.12': 1671 | dependencies: 1672 | '@jridgewell/sourcemap-codec': 1.5.4 1673 | '@jridgewell/trace-mapping': 0.3.29 1674 | 1675 | '@jridgewell/gen-mapping@0.3.13': 1676 | dependencies: 1677 | '@jridgewell/sourcemap-codec': 1.5.5 1678 | '@jridgewell/trace-mapping': 0.3.31 1679 | 1680 | '@jridgewell/resolve-uri@3.1.2': {} 1681 | 1682 | '@jridgewell/sourcemap-codec@1.5.4': {} 1683 | 1684 | '@jridgewell/sourcemap-codec@1.5.5': {} 1685 | 1686 | '@jridgewell/trace-mapping@0.3.29': 1687 | dependencies: 1688 | '@jridgewell/resolve-uri': 3.1.2 1689 | '@jridgewell/sourcemap-codec': 1.5.4 1690 | 1691 | '@jridgewell/trace-mapping@0.3.31': 1692 | dependencies: 1693 | '@jridgewell/resolve-uri': 3.1.2 1694 | '@jridgewell/sourcemap-codec': 1.5.5 1695 | 1696 | '@nodelib/fs.scandir@2.1.5': 1697 | dependencies: 1698 | '@nodelib/fs.stat': 2.0.5 1699 | run-parallel: 1.2.0 1700 | 1701 | '@nodelib/fs.stat@2.0.5': {} 1702 | 1703 | '@nodelib/fs.walk@1.2.8': 1704 | dependencies: 1705 | '@nodelib/fs.scandir': 2.1.5 1706 | fastq: 1.19.1 1707 | 1708 | '@pkgjs/parseargs@0.11.0': 1709 | optional: true 1710 | 1711 | '@pkgr/core@0.2.9': {} 1712 | 1713 | '@rollup/rollup-android-arm-eabi@4.44.2': 1714 | optional: true 1715 | 1716 | '@rollup/rollup-android-arm64@4.44.2': 1717 | optional: true 1718 | 1719 | '@rollup/rollup-darwin-arm64@4.44.2': 1720 | optional: true 1721 | 1722 | '@rollup/rollup-darwin-x64@4.44.2': 1723 | optional: true 1724 | 1725 | '@rollup/rollup-freebsd-arm64@4.44.2': 1726 | optional: true 1727 | 1728 | '@rollup/rollup-freebsd-x64@4.44.2': 1729 | optional: true 1730 | 1731 | '@rollup/rollup-linux-arm-gnueabihf@4.44.2': 1732 | optional: true 1733 | 1734 | '@rollup/rollup-linux-arm-musleabihf@4.44.2': 1735 | optional: true 1736 | 1737 | '@rollup/rollup-linux-arm64-gnu@4.44.2': 1738 | optional: true 1739 | 1740 | '@rollup/rollup-linux-arm64-musl@4.44.2': 1741 | optional: true 1742 | 1743 | '@rollup/rollup-linux-loongarch64-gnu@4.44.2': 1744 | optional: true 1745 | 1746 | '@rollup/rollup-linux-powerpc64le-gnu@4.44.2': 1747 | optional: true 1748 | 1749 | '@rollup/rollup-linux-riscv64-gnu@4.44.2': 1750 | optional: true 1751 | 1752 | '@rollup/rollup-linux-riscv64-musl@4.44.2': 1753 | optional: true 1754 | 1755 | '@rollup/rollup-linux-s390x-gnu@4.44.2': 1756 | optional: true 1757 | 1758 | '@rollup/rollup-linux-x64-gnu@4.44.2': 1759 | optional: true 1760 | 1761 | '@rollup/rollup-linux-x64-musl@4.44.2': 1762 | optional: true 1763 | 1764 | '@rollup/rollup-win32-arm64-msvc@4.44.2': 1765 | optional: true 1766 | 1767 | '@rollup/rollup-win32-ia32-msvc@4.44.2': 1768 | optional: true 1769 | 1770 | '@rollup/rollup-win32-x64-msvc@4.44.2': 1771 | optional: true 1772 | 1773 | '@shahrad/eslint-config@1.0.1(jiti@2.5.1)(typescript@5.9.3)': 1774 | dependencies: 1775 | '@eslint/js': 9.37.0 1776 | eslint: 9.37.0(jiti@2.5.1) 1777 | typescript-eslint: 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 1778 | transitivePeerDependencies: 1779 | - jiti 1780 | - supports-color 1781 | - typescript 1782 | 1783 | '@shahrad/prettier-config@1.2.2(@ianvs/prettier-plugin-sort-imports@4.5.1(prettier@3.6.2))(prettier-plugin-packagejson@2.5.18(prettier@3.6.2))(prettier-plugin-sh@0.15.0(prettier@3.6.2))(prettier@3.6.2)': 1784 | dependencies: 1785 | '@ianvs/prettier-plugin-sort-imports': 4.5.1(prettier@3.6.2) 1786 | prettier: 3.6.2 1787 | prettier-plugin-packagejson: 2.5.18(prettier@3.6.2) 1788 | prettier-plugin-sh: 0.15.0(prettier@3.6.2) 1789 | 1790 | '@shahrad/tsconfig@1.2.0': {} 1791 | 1792 | '@types/chai@5.2.2': 1793 | dependencies: 1794 | '@types/deep-eql': 4.0.2 1795 | 1796 | '@types/deep-eql@4.0.2': {} 1797 | 1798 | '@types/estree@1.0.8': {} 1799 | 1800 | '@types/json-schema@7.0.15': {} 1801 | 1802 | '@types/node@24.7.0': 1803 | dependencies: 1804 | undici-types: 7.14.0 1805 | 1806 | '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3)': 1807 | dependencies: 1808 | '@eslint-community/regexpp': 4.12.1 1809 | '@typescript-eslint/parser': 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 1810 | '@typescript-eslint/scope-manager': 8.45.0 1811 | '@typescript-eslint/type-utils': 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 1812 | '@typescript-eslint/utils': 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 1813 | '@typescript-eslint/visitor-keys': 8.45.0 1814 | eslint: 9.37.0(jiti@2.5.1) 1815 | graphemer: 1.4.0 1816 | ignore: 7.0.5 1817 | natural-compare: 1.4.0 1818 | ts-api-utils: 2.1.0(typescript@5.9.3) 1819 | typescript: 5.9.3 1820 | transitivePeerDependencies: 1821 | - supports-color 1822 | 1823 | '@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3)': 1824 | dependencies: 1825 | '@typescript-eslint/scope-manager': 8.45.0 1826 | '@typescript-eslint/types': 8.45.0 1827 | '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) 1828 | '@typescript-eslint/visitor-keys': 8.45.0 1829 | debug: 4.4.3 1830 | eslint: 9.37.0(jiti@2.5.1) 1831 | typescript: 5.9.3 1832 | transitivePeerDependencies: 1833 | - supports-color 1834 | 1835 | '@typescript-eslint/project-service@8.45.0(typescript@5.9.3)': 1836 | dependencies: 1837 | '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3) 1838 | '@typescript-eslint/types': 8.45.0 1839 | debug: 4.4.3 1840 | typescript: 5.9.3 1841 | transitivePeerDependencies: 1842 | - supports-color 1843 | 1844 | '@typescript-eslint/scope-manager@8.45.0': 1845 | dependencies: 1846 | '@typescript-eslint/types': 8.45.0 1847 | '@typescript-eslint/visitor-keys': 8.45.0 1848 | 1849 | '@typescript-eslint/tsconfig-utils@8.45.0(typescript@5.9.3)': 1850 | dependencies: 1851 | typescript: 5.9.3 1852 | 1853 | '@typescript-eslint/type-utils@8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3)': 1854 | dependencies: 1855 | '@typescript-eslint/types': 8.45.0 1856 | '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) 1857 | '@typescript-eslint/utils': 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 1858 | debug: 4.4.3 1859 | eslint: 9.37.0(jiti@2.5.1) 1860 | ts-api-utils: 2.1.0(typescript@5.9.3) 1861 | typescript: 5.9.3 1862 | transitivePeerDependencies: 1863 | - supports-color 1864 | 1865 | '@typescript-eslint/types@8.45.0': {} 1866 | 1867 | '@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.3)': 1868 | dependencies: 1869 | '@typescript-eslint/project-service': 8.45.0(typescript@5.9.3) 1870 | '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3) 1871 | '@typescript-eslint/types': 8.45.0 1872 | '@typescript-eslint/visitor-keys': 8.45.0 1873 | debug: 4.4.3 1874 | fast-glob: 3.3.3 1875 | is-glob: 4.0.3 1876 | minimatch: 9.0.5 1877 | semver: 7.7.2 1878 | ts-api-utils: 2.1.0(typescript@5.9.3) 1879 | typescript: 5.9.3 1880 | transitivePeerDependencies: 1881 | - supports-color 1882 | 1883 | '@typescript-eslint/utils@8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3)': 1884 | dependencies: 1885 | '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.5.1)) 1886 | '@typescript-eslint/scope-manager': 8.45.0 1887 | '@typescript-eslint/types': 8.45.0 1888 | '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) 1889 | eslint: 9.37.0(jiti@2.5.1) 1890 | typescript: 5.9.3 1891 | transitivePeerDependencies: 1892 | - supports-color 1893 | 1894 | '@typescript-eslint/visitor-keys@8.45.0': 1895 | dependencies: 1896 | '@typescript-eslint/types': 8.45.0 1897 | eslint-visitor-keys: 4.2.1 1898 | 1899 | '@vitest/expect@3.2.4': 1900 | dependencies: 1901 | '@types/chai': 5.2.2 1902 | '@vitest/spy': 3.2.4 1903 | '@vitest/utils': 3.2.4 1904 | chai: 5.2.1 1905 | tinyrainbow: 2.0.0 1906 | 1907 | '@vitest/mocker@3.2.4(vite@7.0.2(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6))': 1908 | dependencies: 1909 | '@vitest/spy': 3.2.4 1910 | estree-walker: 3.0.3 1911 | magic-string: 0.30.17 1912 | optionalDependencies: 1913 | vite: 7.0.2(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6) 1914 | 1915 | '@vitest/pretty-format@3.2.4': 1916 | dependencies: 1917 | tinyrainbow: 2.0.0 1918 | 1919 | '@vitest/runner@3.2.4': 1920 | dependencies: 1921 | '@vitest/utils': 3.2.4 1922 | pathe: 2.0.3 1923 | strip-literal: 3.0.0 1924 | 1925 | '@vitest/snapshot@3.2.4': 1926 | dependencies: 1927 | '@vitest/pretty-format': 3.2.4 1928 | magic-string: 0.30.17 1929 | pathe: 2.0.3 1930 | 1931 | '@vitest/spy@3.2.4': 1932 | dependencies: 1933 | tinyspy: 4.0.3 1934 | 1935 | '@vitest/utils@3.2.4': 1936 | dependencies: 1937 | '@vitest/pretty-format': 3.2.4 1938 | loupe: 3.1.4 1939 | tinyrainbow: 2.0.0 1940 | 1941 | acorn-jsx@5.3.2(acorn@8.15.0): 1942 | dependencies: 1943 | acorn: 8.15.0 1944 | 1945 | acorn@8.15.0: {} 1946 | 1947 | ajv@6.12.6: 1948 | dependencies: 1949 | fast-deep-equal: 3.1.3 1950 | fast-json-stable-stringify: 2.1.0 1951 | json-schema-traverse: 0.4.1 1952 | uri-js: 4.4.1 1953 | 1954 | ansi-regex@5.0.1: {} 1955 | 1956 | ansi-regex@6.1.0: {} 1957 | 1958 | ansi-styles@4.3.0: 1959 | dependencies: 1960 | color-convert: 2.0.1 1961 | 1962 | ansi-styles@6.2.3: {} 1963 | 1964 | any-promise@1.3.0: {} 1965 | 1966 | argparse@2.0.1: {} 1967 | 1968 | assertion-error@2.0.1: {} 1969 | 1970 | balanced-match@1.0.2: {} 1971 | 1972 | brace-expansion@1.1.12: 1973 | dependencies: 1974 | balanced-match: 1.0.2 1975 | concat-map: 0.0.1 1976 | 1977 | brace-expansion@2.0.2: 1978 | dependencies: 1979 | balanced-match: 1.0.2 1980 | 1981 | braces@3.0.3: 1982 | dependencies: 1983 | fill-range: 7.1.1 1984 | 1985 | bundle-require@5.1.0(esbuild@0.25.5): 1986 | dependencies: 1987 | esbuild: 0.25.5 1988 | load-tsconfig: 0.2.5 1989 | 1990 | cac@6.7.14: {} 1991 | 1992 | callsites@3.1.0: {} 1993 | 1994 | chai@5.2.1: 1995 | dependencies: 1996 | assertion-error: 2.0.1 1997 | check-error: 2.1.1 1998 | deep-eql: 5.0.2 1999 | loupe: 3.1.4 2000 | pathval: 2.0.1 2001 | 2002 | chalk@4.1.2: 2003 | dependencies: 2004 | ansi-styles: 4.3.0 2005 | supports-color: 7.2.0 2006 | 2007 | check-error@2.1.1: {} 2008 | 2009 | chokidar@4.0.3: 2010 | dependencies: 2011 | readdirp: 4.1.2 2012 | 2013 | cldr-core@47.0.0: {} 2014 | 2015 | cldr-numbers-full@47.0.0(cldr-core@47.0.0): 2016 | dependencies: 2017 | cldr-core: 47.0.0 2018 | 2019 | color-convert@2.0.1: 2020 | dependencies: 2021 | color-name: 1.1.4 2022 | 2023 | color-name@1.1.4: {} 2024 | 2025 | commander@4.1.1: {} 2026 | 2027 | concat-map@0.0.1: {} 2028 | 2029 | confbox@0.1.8: {} 2030 | 2031 | consola@3.4.2: {} 2032 | 2033 | cross-spawn@7.0.6: 2034 | dependencies: 2035 | path-key: 3.1.1 2036 | shebang-command: 2.0.0 2037 | which: 2.0.2 2038 | 2039 | debug@4.4.1: 2040 | dependencies: 2041 | ms: 2.1.3 2042 | 2043 | debug@4.4.3: 2044 | dependencies: 2045 | ms: 2.1.3 2046 | 2047 | deep-eql@5.0.2: {} 2048 | 2049 | deep-is@0.1.4: {} 2050 | 2051 | detect-indent@7.0.2: {} 2052 | 2053 | detect-newline@4.0.1: {} 2054 | 2055 | eastasianwidth@0.2.0: {} 2056 | 2057 | emoji-regex@8.0.0: {} 2058 | 2059 | emoji-regex@9.2.2: {} 2060 | 2061 | es-module-lexer@1.7.0: {} 2062 | 2063 | esbuild@0.25.5: 2064 | optionalDependencies: 2065 | '@esbuild/aix-ppc64': 0.25.5 2066 | '@esbuild/android-arm': 0.25.5 2067 | '@esbuild/android-arm64': 0.25.5 2068 | '@esbuild/android-x64': 0.25.5 2069 | '@esbuild/darwin-arm64': 0.25.5 2070 | '@esbuild/darwin-x64': 0.25.5 2071 | '@esbuild/freebsd-arm64': 0.25.5 2072 | '@esbuild/freebsd-x64': 0.25.5 2073 | '@esbuild/linux-arm': 0.25.5 2074 | '@esbuild/linux-arm64': 0.25.5 2075 | '@esbuild/linux-ia32': 0.25.5 2076 | '@esbuild/linux-loong64': 0.25.5 2077 | '@esbuild/linux-mips64el': 0.25.5 2078 | '@esbuild/linux-ppc64': 0.25.5 2079 | '@esbuild/linux-riscv64': 0.25.5 2080 | '@esbuild/linux-s390x': 0.25.5 2081 | '@esbuild/linux-x64': 0.25.5 2082 | '@esbuild/netbsd-arm64': 0.25.5 2083 | '@esbuild/netbsd-x64': 0.25.5 2084 | '@esbuild/openbsd-arm64': 0.25.5 2085 | '@esbuild/openbsd-x64': 0.25.5 2086 | '@esbuild/sunos-x64': 0.25.5 2087 | '@esbuild/win32-arm64': 0.25.5 2088 | '@esbuild/win32-ia32': 0.25.5 2089 | '@esbuild/win32-x64': 0.25.5 2090 | 2091 | escape-string-regexp@4.0.0: {} 2092 | 2093 | eslint-scope@8.4.0: 2094 | dependencies: 2095 | esrecurse: 4.3.0 2096 | estraverse: 5.3.0 2097 | 2098 | eslint-visitor-keys@3.4.3: {} 2099 | 2100 | eslint-visitor-keys@4.2.1: {} 2101 | 2102 | eslint@9.37.0(jiti@2.5.1): 2103 | dependencies: 2104 | '@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.5.1)) 2105 | '@eslint-community/regexpp': 4.12.1 2106 | '@eslint/config-array': 0.21.0 2107 | '@eslint/config-helpers': 0.4.0 2108 | '@eslint/core': 0.16.0 2109 | '@eslint/eslintrc': 3.3.1 2110 | '@eslint/js': 9.37.0 2111 | '@eslint/plugin-kit': 0.4.0 2112 | '@humanfs/node': 0.16.7 2113 | '@humanwhocodes/module-importer': 1.0.1 2114 | '@humanwhocodes/retry': 0.4.3 2115 | '@types/estree': 1.0.8 2116 | '@types/json-schema': 7.0.15 2117 | ajv: 6.12.6 2118 | chalk: 4.1.2 2119 | cross-spawn: 7.0.6 2120 | debug: 4.4.3 2121 | escape-string-regexp: 4.0.0 2122 | eslint-scope: 8.4.0 2123 | eslint-visitor-keys: 4.2.1 2124 | espree: 10.4.0 2125 | esquery: 1.6.0 2126 | esutils: 2.0.3 2127 | fast-deep-equal: 3.1.3 2128 | file-entry-cache: 8.0.0 2129 | find-up: 5.0.0 2130 | glob-parent: 6.0.2 2131 | ignore: 5.3.2 2132 | imurmurhash: 0.1.4 2133 | is-glob: 4.0.3 2134 | json-stable-stringify-without-jsonify: 1.0.1 2135 | lodash.merge: 4.6.2 2136 | minimatch: 3.1.2 2137 | natural-compare: 1.4.0 2138 | optionator: 0.9.4 2139 | optionalDependencies: 2140 | jiti: 2.5.1 2141 | transitivePeerDependencies: 2142 | - supports-color 2143 | 2144 | espree@10.4.0: 2145 | dependencies: 2146 | acorn: 8.15.0 2147 | acorn-jsx: 5.3.2(acorn@8.15.0) 2148 | eslint-visitor-keys: 4.2.1 2149 | 2150 | esquery@1.6.0: 2151 | dependencies: 2152 | estraverse: 5.3.0 2153 | 2154 | esrecurse@4.3.0: 2155 | dependencies: 2156 | estraverse: 5.3.0 2157 | 2158 | estraverse@5.3.0: {} 2159 | 2160 | estree-walker@3.0.3: 2161 | dependencies: 2162 | '@types/estree': 1.0.8 2163 | 2164 | esutils@2.0.3: {} 2165 | 2166 | expect-type@1.2.1: {} 2167 | 2168 | fast-deep-equal@3.1.3: {} 2169 | 2170 | fast-glob@3.3.3: 2171 | dependencies: 2172 | '@nodelib/fs.stat': 2.0.5 2173 | '@nodelib/fs.walk': 1.2.8 2174 | glob-parent: 5.1.2 2175 | merge2: 1.4.1 2176 | micromatch: 4.0.8 2177 | 2178 | fast-json-stable-stringify@2.1.0: {} 2179 | 2180 | fast-levenshtein@2.0.6: {} 2181 | 2182 | fastq@1.19.1: 2183 | dependencies: 2184 | reusify: 1.1.0 2185 | 2186 | fdir@6.4.6(picomatch@4.0.2): 2187 | optionalDependencies: 2188 | picomatch: 4.0.2 2189 | 2190 | fdir@6.5.0(picomatch@4.0.3): 2191 | optionalDependencies: 2192 | picomatch: 4.0.3 2193 | 2194 | file-entry-cache@8.0.0: 2195 | dependencies: 2196 | flat-cache: 4.0.1 2197 | 2198 | fill-range@7.1.1: 2199 | dependencies: 2200 | to-regex-range: 5.0.1 2201 | 2202 | find-up@5.0.0: 2203 | dependencies: 2204 | locate-path: 6.0.0 2205 | path-exists: 4.0.0 2206 | 2207 | fix-dts-default-cjs-exports@1.0.1: 2208 | dependencies: 2209 | magic-string: 0.30.17 2210 | mlly: 1.7.4 2211 | rollup: 4.44.2 2212 | 2213 | flat-cache@4.0.1: 2214 | dependencies: 2215 | flatted: 3.3.3 2216 | keyv: 4.5.4 2217 | 2218 | flatted@3.3.3: {} 2219 | 2220 | foreground-child@3.3.1: 2221 | dependencies: 2222 | cross-spawn: 7.0.6 2223 | signal-exit: 4.1.0 2224 | 2225 | fsevents@2.3.3: 2226 | optional: true 2227 | 2228 | get-tsconfig@4.10.1: 2229 | dependencies: 2230 | resolve-pkg-maps: 1.0.0 2231 | 2232 | git-hooks-list@4.1.1: {} 2233 | 2234 | glob-parent@5.1.2: 2235 | dependencies: 2236 | is-glob: 4.0.3 2237 | 2238 | glob-parent@6.0.2: 2239 | dependencies: 2240 | is-glob: 4.0.3 2241 | 2242 | glob@10.4.5: 2243 | dependencies: 2244 | foreground-child: 3.3.1 2245 | jackspeak: 3.4.3 2246 | minimatch: 9.0.5 2247 | minipass: 7.1.2 2248 | package-json-from-dist: 1.0.1 2249 | path-scurry: 1.11.1 2250 | 2251 | globals@14.0.0: {} 2252 | 2253 | globals@16.4.0: {} 2254 | 2255 | graphemer@1.4.0: {} 2256 | 2257 | has-flag@4.0.0: {} 2258 | 2259 | ignore@5.3.2: {} 2260 | 2261 | ignore@7.0.5: {} 2262 | 2263 | import-fresh@3.3.1: 2264 | dependencies: 2265 | parent-module: 1.0.1 2266 | resolve-from: 4.0.0 2267 | 2268 | imurmurhash@0.1.4: {} 2269 | 2270 | is-extglob@2.1.1: {} 2271 | 2272 | is-fullwidth-code-point@3.0.0: {} 2273 | 2274 | is-glob@4.0.3: 2275 | dependencies: 2276 | is-extglob: 2.1.1 2277 | 2278 | is-number@7.0.0: {} 2279 | 2280 | is-plain-obj@4.1.0: {} 2281 | 2282 | isexe@2.0.0: {} 2283 | 2284 | jackspeak@3.4.3: 2285 | dependencies: 2286 | '@isaacs/cliui': 8.0.2 2287 | optionalDependencies: 2288 | '@pkgjs/parseargs': 0.11.0 2289 | 2290 | jiti@2.5.1: 2291 | optional: true 2292 | 2293 | joycon@3.1.1: {} 2294 | 2295 | js-tokens@4.0.0: {} 2296 | 2297 | js-tokens@9.0.1: {} 2298 | 2299 | js-yaml@4.1.0: 2300 | dependencies: 2301 | argparse: 2.0.1 2302 | 2303 | jsesc@3.1.0: {} 2304 | 2305 | json-buffer@3.0.1: {} 2306 | 2307 | json-schema-traverse@0.4.1: {} 2308 | 2309 | json-stable-stringify-without-jsonify@1.0.1: {} 2310 | 2311 | keyv@4.5.4: 2312 | dependencies: 2313 | json-buffer: 3.0.1 2314 | 2315 | levn@0.4.1: 2316 | dependencies: 2317 | prelude-ls: 1.2.1 2318 | type-check: 0.4.0 2319 | 2320 | lilconfig@3.1.3: {} 2321 | 2322 | lines-and-columns@1.2.4: {} 2323 | 2324 | load-tsconfig@0.2.5: {} 2325 | 2326 | locate-path@6.0.0: 2327 | dependencies: 2328 | p-locate: 5.0.0 2329 | 2330 | lodash.merge@4.6.2: {} 2331 | 2332 | lodash.sortby@4.7.0: {} 2333 | 2334 | loupe@3.1.4: {} 2335 | 2336 | lru-cache@10.4.3: {} 2337 | 2338 | magic-string@0.30.17: 2339 | dependencies: 2340 | '@jridgewell/sourcemap-codec': 1.5.4 2341 | 2342 | merge2@1.4.1: {} 2343 | 2344 | micromatch@4.0.8: 2345 | dependencies: 2346 | braces: 3.0.3 2347 | picomatch: 2.3.1 2348 | 2349 | minimatch@3.1.2: 2350 | dependencies: 2351 | brace-expansion: 1.1.12 2352 | 2353 | minimatch@9.0.5: 2354 | dependencies: 2355 | brace-expansion: 2.0.2 2356 | 2357 | minipass@7.1.2: {} 2358 | 2359 | mlly@1.7.4: 2360 | dependencies: 2361 | acorn: 8.15.0 2362 | pathe: 2.0.3 2363 | pkg-types: 1.3.1 2364 | ufo: 1.6.1 2365 | 2366 | ms@2.1.3: {} 2367 | 2368 | mvdan-sh@0.10.1: {} 2369 | 2370 | mz@2.7.0: 2371 | dependencies: 2372 | any-promise: 1.3.0 2373 | object-assign: 4.1.1 2374 | thenify-all: 1.6.0 2375 | 2376 | nanoid@3.3.11: {} 2377 | 2378 | natural-compare@1.4.0: {} 2379 | 2380 | object-assign@4.1.1: {} 2381 | 2382 | optionator@0.9.4: 2383 | dependencies: 2384 | deep-is: 0.1.4 2385 | fast-levenshtein: 2.0.6 2386 | levn: 0.4.1 2387 | prelude-ls: 1.2.1 2388 | type-check: 0.4.0 2389 | word-wrap: 1.2.5 2390 | 2391 | p-limit@3.1.0: 2392 | dependencies: 2393 | yocto-queue: 0.1.0 2394 | 2395 | p-locate@5.0.0: 2396 | dependencies: 2397 | p-limit: 3.1.0 2398 | 2399 | package-json-from-dist@1.0.1: {} 2400 | 2401 | parent-module@1.0.1: 2402 | dependencies: 2403 | callsites: 3.1.0 2404 | 2405 | path-exists@4.0.0: {} 2406 | 2407 | path-key@3.1.1: {} 2408 | 2409 | path-scurry@1.11.1: 2410 | dependencies: 2411 | lru-cache: 10.4.3 2412 | minipass: 7.1.2 2413 | 2414 | pathe@2.0.3: {} 2415 | 2416 | pathval@2.0.1: {} 2417 | 2418 | picocolors@1.1.1: {} 2419 | 2420 | picomatch@2.3.1: {} 2421 | 2422 | picomatch@4.0.2: {} 2423 | 2424 | picomatch@4.0.3: {} 2425 | 2426 | pirates@4.0.7: {} 2427 | 2428 | pkg-types@1.3.1: 2429 | dependencies: 2430 | confbox: 0.1.8 2431 | mlly: 1.7.4 2432 | pathe: 2.0.3 2433 | 2434 | postcss-load-config@6.0.1(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.6): 2435 | dependencies: 2436 | lilconfig: 3.1.3 2437 | optionalDependencies: 2438 | jiti: 2.5.1 2439 | postcss: 8.5.6 2440 | tsx: 4.20.6 2441 | 2442 | postcss@8.5.6: 2443 | dependencies: 2444 | nanoid: 3.3.11 2445 | picocolors: 1.1.1 2446 | source-map-js: 1.2.1 2447 | 2448 | prelude-ls@1.2.1: {} 2449 | 2450 | prettier-plugin-packagejson@2.5.18(prettier@3.6.2): 2451 | dependencies: 2452 | sort-package-json: 3.4.0 2453 | synckit: 0.11.8 2454 | optionalDependencies: 2455 | prettier: 3.6.2 2456 | 2457 | prettier-plugin-sh@0.15.0(prettier@3.6.2): 2458 | dependencies: 2459 | mvdan-sh: 0.10.1 2460 | prettier: 3.6.2 2461 | sh-syntax: 0.4.2 2462 | 2463 | prettier@3.6.2: {} 2464 | 2465 | punycode@2.3.1: {} 2466 | 2467 | queue-microtask@1.2.3: {} 2468 | 2469 | readdirp@4.1.2: {} 2470 | 2471 | resolve-from@4.0.0: {} 2472 | 2473 | resolve-from@5.0.0: {} 2474 | 2475 | resolve-pkg-maps@1.0.0: {} 2476 | 2477 | reusify@1.1.0: {} 2478 | 2479 | rollup@4.44.2: 2480 | dependencies: 2481 | '@types/estree': 1.0.8 2482 | optionalDependencies: 2483 | '@rollup/rollup-android-arm-eabi': 4.44.2 2484 | '@rollup/rollup-android-arm64': 4.44.2 2485 | '@rollup/rollup-darwin-arm64': 4.44.2 2486 | '@rollup/rollup-darwin-x64': 4.44.2 2487 | '@rollup/rollup-freebsd-arm64': 4.44.2 2488 | '@rollup/rollup-freebsd-x64': 4.44.2 2489 | '@rollup/rollup-linux-arm-gnueabihf': 4.44.2 2490 | '@rollup/rollup-linux-arm-musleabihf': 4.44.2 2491 | '@rollup/rollup-linux-arm64-gnu': 4.44.2 2492 | '@rollup/rollup-linux-arm64-musl': 4.44.2 2493 | '@rollup/rollup-linux-loongarch64-gnu': 4.44.2 2494 | '@rollup/rollup-linux-powerpc64le-gnu': 4.44.2 2495 | '@rollup/rollup-linux-riscv64-gnu': 4.44.2 2496 | '@rollup/rollup-linux-riscv64-musl': 4.44.2 2497 | '@rollup/rollup-linux-s390x-gnu': 4.44.2 2498 | '@rollup/rollup-linux-x64-gnu': 4.44.2 2499 | '@rollup/rollup-linux-x64-musl': 4.44.2 2500 | '@rollup/rollup-win32-arm64-msvc': 4.44.2 2501 | '@rollup/rollup-win32-ia32-msvc': 4.44.2 2502 | '@rollup/rollup-win32-x64-msvc': 4.44.2 2503 | fsevents: 2.3.3 2504 | 2505 | run-parallel@1.2.0: 2506 | dependencies: 2507 | queue-microtask: 1.2.3 2508 | 2509 | semver@7.7.2: {} 2510 | 2511 | sh-syntax@0.4.2: 2512 | dependencies: 2513 | tslib: 2.8.1 2514 | 2515 | shebang-command@2.0.0: 2516 | dependencies: 2517 | shebang-regex: 3.0.0 2518 | 2519 | shebang-regex@3.0.0: {} 2520 | 2521 | siginfo@2.0.0: {} 2522 | 2523 | signal-exit@4.1.0: {} 2524 | 2525 | sort-object-keys@1.1.3: {} 2526 | 2527 | sort-package-json@3.4.0: 2528 | dependencies: 2529 | detect-indent: 7.0.2 2530 | detect-newline: 4.0.1 2531 | git-hooks-list: 4.1.1 2532 | is-plain-obj: 4.1.0 2533 | semver: 7.7.2 2534 | sort-object-keys: 1.1.3 2535 | tinyglobby: 0.2.15 2536 | 2537 | source-map-js@1.2.1: {} 2538 | 2539 | source-map@0.8.0-beta.0: 2540 | dependencies: 2541 | whatwg-url: 7.1.0 2542 | 2543 | stackback@0.0.2: {} 2544 | 2545 | std-env@3.9.0: {} 2546 | 2547 | string-width@4.2.3: 2548 | dependencies: 2549 | emoji-regex: 8.0.0 2550 | is-fullwidth-code-point: 3.0.0 2551 | strip-ansi: 6.0.1 2552 | 2553 | string-width@5.1.2: 2554 | dependencies: 2555 | eastasianwidth: 0.2.0 2556 | emoji-regex: 9.2.2 2557 | strip-ansi: 7.1.0 2558 | 2559 | strip-ansi@6.0.1: 2560 | dependencies: 2561 | ansi-regex: 5.0.1 2562 | 2563 | strip-ansi@7.1.0: 2564 | dependencies: 2565 | ansi-regex: 6.1.0 2566 | 2567 | strip-json-comments@3.1.1: {} 2568 | 2569 | strip-literal@3.0.0: 2570 | dependencies: 2571 | js-tokens: 9.0.1 2572 | 2573 | sucrase@3.35.0: 2574 | dependencies: 2575 | '@jridgewell/gen-mapping': 0.3.12 2576 | commander: 4.1.1 2577 | glob: 10.4.5 2578 | lines-and-columns: 1.2.4 2579 | mz: 2.7.0 2580 | pirates: 4.0.7 2581 | ts-interface-checker: 0.1.13 2582 | 2583 | supports-color@7.2.0: 2584 | dependencies: 2585 | has-flag: 4.0.0 2586 | 2587 | synckit@0.11.8: 2588 | dependencies: 2589 | '@pkgr/core': 0.2.9 2590 | 2591 | thenify-all@1.6.0: 2592 | dependencies: 2593 | thenify: 3.3.1 2594 | 2595 | thenify@3.3.1: 2596 | dependencies: 2597 | any-promise: 1.3.0 2598 | 2599 | tinybench@2.9.0: {} 2600 | 2601 | tinyexec@0.3.2: {} 2602 | 2603 | tinyglobby@0.2.14: 2604 | dependencies: 2605 | fdir: 6.4.6(picomatch@4.0.2) 2606 | picomatch: 4.0.2 2607 | 2608 | tinyglobby@0.2.15: 2609 | dependencies: 2610 | fdir: 6.5.0(picomatch@4.0.3) 2611 | picomatch: 4.0.3 2612 | 2613 | tinypool@1.1.1: {} 2614 | 2615 | tinyrainbow@2.0.0: {} 2616 | 2617 | tinyspy@4.0.3: {} 2618 | 2619 | to-regex-range@5.0.1: 2620 | dependencies: 2621 | is-number: 7.0.0 2622 | 2623 | tr46@1.0.1: 2624 | dependencies: 2625 | punycode: 2.3.1 2626 | 2627 | tree-kill@1.2.2: {} 2628 | 2629 | ts-api-utils@2.1.0(typescript@5.9.3): 2630 | dependencies: 2631 | typescript: 5.9.3 2632 | 2633 | ts-interface-checker@0.1.13: {} 2634 | 2635 | tslib@2.8.1: {} 2636 | 2637 | tsup@8.5.0(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3): 2638 | dependencies: 2639 | bundle-require: 5.1.0(esbuild@0.25.5) 2640 | cac: 6.7.14 2641 | chokidar: 4.0.3 2642 | consola: 3.4.2 2643 | debug: 4.4.1 2644 | esbuild: 0.25.5 2645 | fix-dts-default-cjs-exports: 1.0.1 2646 | joycon: 3.1.1 2647 | picocolors: 1.1.1 2648 | postcss-load-config: 6.0.1(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.6) 2649 | resolve-from: 5.0.0 2650 | rollup: 4.44.2 2651 | source-map: 0.8.0-beta.0 2652 | sucrase: 3.35.0 2653 | tinyexec: 0.3.2 2654 | tinyglobby: 0.2.14 2655 | tree-kill: 1.2.2 2656 | optionalDependencies: 2657 | postcss: 8.5.6 2658 | typescript: 5.9.3 2659 | transitivePeerDependencies: 2660 | - jiti 2661 | - supports-color 2662 | - tsx 2663 | - yaml 2664 | 2665 | tsx@4.20.6: 2666 | dependencies: 2667 | esbuild: 0.25.5 2668 | get-tsconfig: 4.10.1 2669 | optionalDependencies: 2670 | fsevents: 2.3.3 2671 | 2672 | type-check@0.4.0: 2673 | dependencies: 2674 | prelude-ls: 1.2.1 2675 | 2676 | typescript-eslint@8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3): 2677 | dependencies: 2678 | '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3))(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 2679 | '@typescript-eslint/parser': 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 2680 | '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3) 2681 | '@typescript-eslint/utils': 8.45.0(eslint@9.37.0(jiti@2.5.1))(typescript@5.9.3) 2682 | eslint: 9.37.0(jiti@2.5.1) 2683 | typescript: 5.9.3 2684 | transitivePeerDependencies: 2685 | - supports-color 2686 | 2687 | typescript@5.9.3: {} 2688 | 2689 | ufo@1.6.1: {} 2690 | 2691 | undici-types@7.14.0: {} 2692 | 2693 | uri-js@4.4.1: 2694 | dependencies: 2695 | punycode: 2.3.1 2696 | 2697 | vite-node@3.2.4(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6): 2698 | dependencies: 2699 | cac: 6.7.14 2700 | debug: 4.4.3 2701 | es-module-lexer: 1.7.0 2702 | pathe: 2.0.3 2703 | vite: 7.0.2(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6) 2704 | transitivePeerDependencies: 2705 | - '@types/node' 2706 | - jiti 2707 | - less 2708 | - lightningcss 2709 | - sass 2710 | - sass-embedded 2711 | - stylus 2712 | - sugarss 2713 | - supports-color 2714 | - terser 2715 | - tsx 2716 | - yaml 2717 | 2718 | vite@7.0.2(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6): 2719 | dependencies: 2720 | esbuild: 0.25.5 2721 | fdir: 6.4.6(picomatch@4.0.2) 2722 | picomatch: 4.0.2 2723 | postcss: 8.5.6 2724 | rollup: 4.44.2 2725 | tinyglobby: 0.2.14 2726 | optionalDependencies: 2727 | '@types/node': 24.7.0 2728 | fsevents: 2.3.3 2729 | jiti: 2.5.1 2730 | tsx: 4.20.6 2731 | 2732 | vitest@3.2.4(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6): 2733 | dependencies: 2734 | '@types/chai': 5.2.2 2735 | '@vitest/expect': 3.2.4 2736 | '@vitest/mocker': 3.2.4(vite@7.0.2(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6)) 2737 | '@vitest/pretty-format': 3.2.4 2738 | '@vitest/runner': 3.2.4 2739 | '@vitest/snapshot': 3.2.4 2740 | '@vitest/spy': 3.2.4 2741 | '@vitest/utils': 3.2.4 2742 | chai: 5.2.1 2743 | debug: 4.4.1 2744 | expect-type: 1.2.1 2745 | magic-string: 0.30.17 2746 | pathe: 2.0.3 2747 | picomatch: 4.0.2 2748 | std-env: 3.9.0 2749 | tinybench: 2.9.0 2750 | tinyexec: 0.3.2 2751 | tinyglobby: 0.2.14 2752 | tinypool: 1.1.1 2753 | tinyrainbow: 2.0.0 2754 | vite: 7.0.2(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6) 2755 | vite-node: 3.2.4(@types/node@24.7.0)(jiti@2.5.1)(tsx@4.20.6) 2756 | why-is-node-running: 2.3.0 2757 | optionalDependencies: 2758 | '@types/node': 24.7.0 2759 | transitivePeerDependencies: 2760 | - jiti 2761 | - less 2762 | - lightningcss 2763 | - msw 2764 | - sass 2765 | - sass-embedded 2766 | - stylus 2767 | - sugarss 2768 | - supports-color 2769 | - terser 2770 | - tsx 2771 | - yaml 2772 | 2773 | webidl-conversions@4.0.2: {} 2774 | 2775 | whatwg-url@7.1.0: 2776 | dependencies: 2777 | lodash.sortby: 4.7.0 2778 | tr46: 1.0.1 2779 | webidl-conversions: 4.0.2 2780 | 2781 | which@2.0.2: 2782 | dependencies: 2783 | isexe: 2.0.0 2784 | 2785 | why-is-node-running@2.3.0: 2786 | dependencies: 2787 | siginfo: 2.0.0 2788 | stackback: 0.0.2 2789 | 2790 | word-wrap@1.2.5: {} 2791 | 2792 | wrap-ansi@7.0.0: 2793 | dependencies: 2794 | ansi-styles: 4.3.0 2795 | string-width: 4.2.3 2796 | strip-ansi: 6.0.1 2797 | 2798 | wrap-ansi@8.1.0: 2799 | dependencies: 2800 | ansi-styles: 6.2.3 2801 | string-width: 5.1.2 2802 | strip-ansi: 7.1.0 2803 | 2804 | yocto-queue@0.1.0: {} 2805 | --------------------------------------------------------------------------------