├── .tool-versions ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── run-unit-tests.yml │ └── release.yml ├── src ├── types.ts ├── index.ts ├── CalledWithFn.ts ├── Matchers.ts ├── Mock.ts ├── Matchers.spec.ts └── Mock.spec.ts ├── .gitignore ├── .prettierrc ├── .editorconfig ├── example ├── src │ ├── index.ts │ └── mock-example.spec.ts ├── tsconfig.json ├── package.json └── pnpm-lock.yaml ├── vitest.config.mts ├── .vscode └── launch.json ├── tsconfig.json ├── LICENSE ├── rollup.config.mjs ├── eslint.config.mjs ├── package.json └── README.md /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 22.14.0 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @eratio08 2 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type FallbackImplementation = (...args: Y) => T 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | coverage 4 | lib/ 5 | node_modules/ 6 | example/src/*.js 7 | example/src/*.d.ts 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "tabWidth": 4, 4 | "singleQuote": true, 5 | "semi": false 6 | } 7 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Mock' 2 | export type * from './Mock' 3 | export * from './CalledWithFn' 4 | export * from './Matchers' 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | charset = utf-8 7 | 8 | [*.{ts,js,mjs}] 9 | indent_style = space 10 | 11 | [*.json] 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [*.{yaml,yml}] 16 | indent_style = space 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /example/src/index.ts: -------------------------------------------------------------------------------- 1 | import { mockDeep, DeepMockProxy } from 'vitest-mock-extended' 2 | 3 | type thing = { 4 | property: string 5 | } 6 | 7 | export type MockContext = { 8 | prisma: DeepMockProxy 9 | } 10 | 11 | export const createMockContext = (): MockContext => { 12 | return { 13 | prisma: mockDeep(), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig, configDefaults } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | ...configDefaults, 6 | includeSource: ['./src'], 7 | 8 | exclude: [...configDefaults.exclude, 'lib/**'], 9 | coverage: { 10 | ...configDefaults.coverage, 11 | exclude: [...(configDefaults.coverage?.exclude ?? []), '**/*.spec.ts', 'lib/**'], 12 | }, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ES2022", 5 | "moduleResolution": "Bundler", 6 | "declaration": true, 7 | "lib": [ 8 | "ES2022" 9 | ], 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "alwaysStrict": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": [ 19 | "src" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "npm" 6 | commit-message: 7 | prefix: "chore: " 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | 12 | - package-ecosystem: "npm" 13 | directory: "/example" 14 | commit-message: 15 | prefix: "chore: " 16 | schedule: 17 | interval: "daily" 18 | 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | commit-message: 22 | prefix: "chore: " 23 | schedule: 24 | interval: "weekly" 25 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Debug", 11 | "skipFiles": [ 12 | "/**" 13 | ], 14 | "program": "${workspaceFolder}/lib/esm/index.js", 15 | "preLaunchTask": "tsc: build - tsconfig.json", 16 | "outFiles": [ 17 | "${workspaceFolder}/lib/**/*.js" 18 | ] 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "pnpm type-check && vitest run --coverage", 9 | "ts-node-dev": "ts-node --esm src/index.ts", 10 | "tsm-dev": "tsm src/index.ts", 11 | "type-check": "tsc --noEmit" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "@types/node": "24.10.1", 18 | "@vitest/coverage-v8": "3.0.6", 19 | "ts-node": "10.9.2", 20 | "tsm": "2.3.0", 21 | "typescript": "5.5.3", 22 | "vitest": "3.0.6", 23 | "vitest-mock-extended": "link:.." 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/src/mock-example.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest' 2 | import { mock, mockDeep } from 'vitest-mock-extended' 3 | 4 | describe('Use mock example', () => { 5 | type SomeType = { fieldC: string } 6 | interface SomeInterface { 7 | fieldA: string 8 | fieldB: SomeType 9 | } 10 | 11 | it('should mock interfaces and types', () => { 12 | const mockedInterface = mock({ fieldA: 'valueA', fieldB: { fieldC: 'valueC' } }) 13 | 14 | expect(mockedInterface.fieldA).toBe('valueA') 15 | expect(mockedInterface.fieldB).contains({ fieldC: 'valueC' }) 16 | }) 17 | 18 | it('should mock returned object', () => { 19 | const mockedInterface = mockDeep({ fieldA: 'valueA' }) 20 | 21 | expect(mockedInterface.fieldA).toBe('valueA') 22 | expect(mockedInterface.fieldB.fieldC).not.toBeNull() // returns spy function 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "esModuleInterop": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "skipLibCheck": true, 7 | "declaration": true, 8 | "declarationMap": true, 9 | "allowSyntheticDefaultImports": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "alwaysStrict": true, 13 | "allowJs": false, 14 | "lib": [ 15 | "ES2022", 16 | "DOM" 17 | ], 18 | "target": "ES2022", 19 | "module": "ES2022", 20 | "moduleResolution": "Bundler", 21 | "isolatedModules": true, 22 | "outDir": "lib", 23 | "declarationDir": "lib/types" 24 | }, 25 | "files": [ 26 | "src/index.ts" 27 | ], 28 | "include": [ 29 | "src", 30 | "**/*.mts" 31 | ], 32 | "exclude": [ 33 | "lib" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Marc McIntyre 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 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import pkg from './package.json' with { type: "json" }; 2 | import esbuild from 'rollup-plugin-esbuild'; 3 | import { dts } from 'rollup-plugin-dts'; 4 | import { defineConfig } from 'rollup'; 5 | 6 | const external = [...Object.keys(pkg.dependencies), ...Object.keys(pkg.peerDependencies)] 7 | const input = "src/index.ts" 8 | 9 | const configs = [ 10 | defineConfig({ 11 | input, 12 | plugins: [ 13 | esbuild({ 14 | tsconfig: 'tsconfig.json', 15 | }), 16 | ], 17 | output: [ 18 | { 19 | file: 'lib/esm/index.js', 20 | format: 'es', 21 | sourcemap: true, 22 | }, 23 | { 24 | file: 'lib/index.cjs', 25 | format: 'cjs', 26 | sourcemap: true, 27 | }, 28 | ], 29 | external 30 | }), 31 | defineConfig({ 32 | input, 33 | plugins: [dts()], 34 | output: [ 35 | { 36 | file: `lib/esm/index.d.ts`, 37 | format: 'es', 38 | sourcemap: true, 39 | }, 40 | { 41 | file: `lib/index.d.cts`, 42 | format: 'cjs', 43 | sourcemap: true, 44 | }, 45 | ], 46 | external 47 | }), 48 | ]; 49 | 50 | export default configs; 51 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js'; 2 | import tseslint from 'typescript-eslint'; 3 | import prettierConfig from 'eslint-config-prettier'; 4 | 5 | export default tseslint.config( 6 | eslint.configs.recommended, 7 | ...tseslint.configs.recommendedTypeChecked, 8 | { 9 | rules: { 10 | '@typescript-eslint/no-explicit-any': 'off', 11 | '@typescript-eslint/no-unsafe-argument': 'off', 12 | '@typescript-eslint/no-unsafe-member-access': 'warn', 13 | '@typescript-eslint/no-unsafe-call': 'warn', 14 | '@typescript-eslint/no-unsafe-assignment': 'warn', 15 | '@typescript-eslint/no-unsafe-return': 'warn', 16 | '@typescript-eslint/no-unused-vars': 'warn', 17 | '@typescript-eslint/unbound-method': 'warn', 18 | '@typescript-eslint/require-await': 'warn', 19 | '@typescript-eslint/ban-ts-comment': 'warn', 20 | }, 21 | }, 22 | { 23 | languageOptions: { 24 | parserOptions: { 25 | project: true, 26 | tsconfigRootDir: import.meta.dirname, 27 | }, 28 | }, 29 | }, 30 | { 31 | files: [ 32 | '**/*.mjs' 33 | ], 34 | ...tseslint.configs.disableTypeChecked, 35 | }, 36 | { 37 | ignores: ['lib/**', '**/coverage/**'] 38 | }, 39 | prettierConfig, 40 | ); 41 | -------------------------------------------------------------------------------- /.github/workflows/run-unit-tests.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - "main" 7 | 8 | concurrency: 9 | group: ${{ github.workflow }} - ${{ github.event.pull_request.id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | pull-request: 14 | runs-on: ubuntu-latest 15 | steps: 16 | # https://github.com/marketplace/actions/checkout 17 | - name: Checkout Repository 18 | uses: actions/checkout@v6 19 | 20 | # https://github.com/marketplace/actions/setup-pnpm 21 | - name: Install pnpm 22 | uses: pnpm/action-setup@v4.2.0 23 | with: 24 | version: latest 25 | run_install: false 26 | 27 | # https://github.com/marketplace/actions/setup-node-js-environment 28 | - name: Setup NodeJS 29 | uses: actions/setup-node@v6 30 | with: 31 | cache: pnpm 32 | node-version: lts/* 33 | check-latest: true 34 | 35 | - name: Install dependencies 36 | run: pnpm recursive install ${{ github.actor != 'dependabot[bot]' && '--frozen-lockfile' || '--no-frozen-lockfile' }} 37 | 38 | - run: echo "${{ toJSON(env) }}" 39 | 40 | - name: Build 41 | run: pnpm build 42 | 43 | - name: Lint 44 | run: pnpm lint 45 | 46 | - name: Unit-Tests 47 | run: pnpm test 48 | 49 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | run-name: Release by ${{ github.actor }} 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | dry-run: 8 | description: dry-run 9 | required: true 10 | type: boolean 11 | default: true 12 | push: 13 | tags: 14 | - 'v*' 15 | 16 | jobs: 17 | release: 18 | name: Release 19 | runs-on: ubuntu-latest 20 | steps: 21 | # https://github.com/marketplace/actions/checkout 22 | - name: Checkout Repository 23 | uses: actions/checkout@v6 24 | 25 | # https://github.com/marketplace/actions/setup-pnpm 26 | - uses: pnpm/action-setup@v4.2.0 27 | name: Install pnpm 28 | id: pnpm-install 29 | with: 30 | version: latest 31 | run_install: false 32 | 33 | # https://github.com/marketplace/actions/setup-node-js-environment 34 | - name: Setup NodeJS 35 | uses: actions/setup-node@v6 36 | with: 37 | cache: pnpm 38 | node-version: lts/* 39 | check-latest: true 40 | 41 | - name: Install dependencies 42 | run: pnpm install --frozen-lockfile 43 | 44 | - name: Build Lib 45 | run: pnpm build 46 | 47 | - name: Release 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 51 | run: npx semantic-release ${{ inputs.dry-run && '-d' || '' }} 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vitest-mock-extended", 3 | "version": "3.0.0", 4 | "homepage": "https://github.com/eratio08/vitest-mock-extended", 5 | "description": "Type safe mocking extensions for vitest, forked from jest-mock-extended", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/eratio08/vitest-mock-extended" 9 | }, 10 | "author": "Eike Lurz ", 11 | "license": "MIT", 12 | "files": [ 13 | "lib/**/*" 14 | ], 15 | "main": "./lib/esm/index.js", 16 | "types": "./lib/esm/index.d.ts", 17 | "module": "./lib/esm/index.js", 18 | "exports": { 19 | ".": { 20 | "import": { 21 | "types": "./lib/esm/index.d.ts", 22 | "default": "./lib/esm/index.js" 23 | }, 24 | "require": { 25 | "types": "./lib/index.d.cts", 26 | "default": "./lib/index.cjs" 27 | } 28 | } 29 | }, 30 | "type": "module", 31 | "scripts": { 32 | "test": "vitest run --coverage", 33 | "clean": "rimraf coverage lib", 34 | "lint": "eslint .", 35 | "lint:fix": "eslint --fix .", 36 | "lint:fix-example": "eslint --fix example/src", 37 | "build": "pnpm clean && pnpm build:rollup", 38 | "build:rollup": "rollup -c" 39 | }, 40 | "dependencies": { 41 | "ts-essentials": ">=10.0.0" 42 | }, 43 | "devDependencies": { 44 | "@eslint/js": "9.39.2", 45 | "@vitest/coverage-v8": "3.0.6", 46 | "esbuild": "0.27.2", 47 | "eslint": "9.39.2", 48 | "eslint-config-prettier": "10.1.8", 49 | "rimraf": "6.1.2", 50 | "rollup": "4.53.5", 51 | "rollup-plugin-dts": "6.3.0", 52 | "rollup-plugin-esbuild": "6.2.1", 53 | "semantic-release": "25.0.2", 54 | "typescript": "5.9.3", 55 | "typescript-eslint": "8.50.0", 56 | "vitest": "3.0.6" 57 | }, 58 | "peerDependencies": { 59 | "typescript": "3.x || 4.x || 5.x", 60 | "vitest": ">=3.0.0" 61 | }, 62 | "release": { 63 | "branches": [ 64 | "main" 65 | ] 66 | }, 67 | "publishConfig": { 68 | "access": "public" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/CalledWithFn.ts: -------------------------------------------------------------------------------- 1 | import { CalledWithMock } from './Mock' 2 | import { Matcher, MatchersOrLiterals } from './Matchers' 3 | import { FallbackImplementation } from './types' 4 | import { vi, Mock } from 'vitest' 5 | 6 | interface CalledWithStackItem { 7 | args: MatchersOrLiterals 8 | calledWithFn: Mock> 9 | } 10 | 11 | interface VitestAsymmetricMatcher { 12 | asymmetricMatch(...args: any[]): boolean 13 | } 14 | 15 | function isVitestAsymmetricMatcher(obj: any): obj is VitestAsymmetricMatcher { 16 | return !!obj && typeof obj === 'object' 17 | && 'asymmetricMatch' in obj 18 | && typeof obj.asymmetricMatch === 'function' 19 | } 20 | 21 | const checkCalledWith = ( 22 | calledWithStack: CalledWithStackItem[], 23 | actualArgs: Y, 24 | fallbackMockImplementation?: FallbackImplementation, 25 | ): T => { 26 | const calledWithInstance = calledWithStack.find((instance) => 27 | instance.args.every((matcher, i) => { 28 | if (matcher instanceof Matcher) { 29 | return matcher.asymmetricMatch(actualArgs[i]) 30 | } 31 | 32 | if (isVitestAsymmetricMatcher(matcher)) { 33 | return matcher.asymmetricMatch(actualArgs[i]) 34 | } 35 | 36 | return actualArgs[i] === matcher 37 | }), 38 | ) 39 | 40 | // @ts-ignore 41 | return calledWithInstance 42 | ? calledWithInstance.calledWithFn(...actualArgs) 43 | : fallbackMockImplementation && fallbackMockImplementation(...actualArgs) 44 | } 45 | 46 | type CalledWithFnArgs = { fallbackMockImplementation?: FallbackImplementation } 47 | 48 | const calledWithFn = ({ fallbackMockImplementation }: CalledWithFnArgs = {}): CalledWithMock => { 49 | const fn: Mock> = fallbackMockImplementation ? vi.fn(fallbackMockImplementation) : vi.fn() 50 | let calledWithStack: CalledWithStackItem[] = [] 51 | 52 | ; (fn as CalledWithMock).calledWith = (...args) => { 53 | // We create new function to delegate any interactions (mockReturnValue etc.) to for this set of args. 54 | // If that set of args is matched, we just call that vi.fn() for the result. 55 | const calledWithFn: Mock> = fallbackMockImplementation ? vi.fn(fallbackMockImplementation) : vi.fn() 56 | const mockImplementation = fn.getMockImplementation() 57 | if ( 58 | !mockImplementation || 59 | fn.getMockImplementation()?.name === 'implementation' || 60 | mockImplementation === fallbackMockImplementation 61 | ) { 62 | // Our original function gets a mock implementation which handles the matching 63 | fn.mockImplementation((...args: Y) => checkCalledWith(calledWithStack, args, fallbackMockImplementation)) 64 | calledWithStack = [] 65 | } 66 | calledWithStack.unshift({ args, calledWithFn }) 67 | 68 | return calledWithFn 69 | } 70 | 71 | return fn as CalledWithMock 72 | } 73 | 74 | export { calledWithFn } 75 | -------------------------------------------------------------------------------- /src/Matchers.ts: -------------------------------------------------------------------------------- 1 | type MatcherFn = (actualValue: T) => boolean 2 | 3 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 4 | interface MatcherLike { 5 | asymmetricMatch(other: unknown): boolean 6 | toString(): string 7 | getExpectedType?(): string 8 | toAsymmetricMatcher?(): string 9 | } 10 | 11 | // needs to be a class so we can instanceof 12 | class Matcher implements MatcherLike { 13 | $$typeof: symbol 14 | inverse?: boolean 15 | 16 | constructor( 17 | readonly asymmetricMatch: MatcherFn, 18 | private readonly description: string, 19 | ) { 20 | this.$$typeof = Symbol.for('vi.asymmetricMatcher') 21 | } 22 | 23 | toString() { 24 | return this.description 25 | } 26 | 27 | toAsymmetricMatcher() { 28 | return this.description 29 | } 30 | 31 | getExpectedType() { 32 | return 'undefined' 33 | } 34 | } 35 | 36 | class CaptorMatcher { 37 | $$typeof: symbol 38 | public readonly asymmetricMatch: MatcherFn 39 | public readonly value!: T 40 | public readonly values: T[] = [] 41 | constructor() { 42 | this.$$typeof = Symbol.for('vi.asymmetricMatcher') 43 | 44 | this.asymmetricMatch = (actualValue: T) => { 45 | // @ts-expect-error value should be read-only but we need to set it 46 | this.value = actualValue 47 | this.values.push(actualValue) 48 | return true 49 | } 50 | } 51 | 52 | getExpectedType() { 53 | return 'Object' 54 | } 55 | 56 | toString() { 57 | return 'captor' 58 | } 59 | 60 | toAsymmetricMatcher() { 61 | return 'captor' 62 | } 63 | } 64 | 65 | interface MatcherCreator { 66 | (expectedValue?: E): Matcher 67 | } 68 | 69 | type MatchersOrLiterals = { [K in keyof Y]: MatcherLike | Y[K] } 70 | 71 | const any: MatcherCreator = () => new Matcher(() => true, 'any()') 72 | const anyBoolean: MatcherCreator = () => new Matcher((actualValue: boolean) => typeof actualValue === 'boolean', 'anyBoolean()') 73 | const anyNumber: MatcherCreator = () => 74 | new Matcher((actualValue) => typeof actualValue === 'number' && !isNaN(actualValue), 'anyNumber()') 75 | const anyString: MatcherCreator = () => new Matcher((actualValue: string) => typeof actualValue === 'string', 'anyString()') 76 | const anyFunction: MatcherCreator = () => 77 | new Matcher((actualValue: CallableFunction) => typeof actualValue === 'function', 'anyFunction()') 78 | const anySymbol: MatcherCreator = () => new Matcher((actualValue) => typeof actualValue === 'symbol', 'anySymbol()') 79 | const anyObject: MatcherCreator = () => 80 | new Matcher((actualValue) => typeof actualValue === 'object' && actualValue !== null, 'anyObject()') 81 | 82 | const anyArray: MatcherCreator = () => new Matcher((actualValue) => Array.isArray(actualValue), 'anyArray()') 83 | const anyMap: MatcherCreator> = () => new Matcher((actualValue) => actualValue instanceof Map, 'anyMap()') 84 | const anySet: MatcherCreator> = () => new Matcher((actualValue) => actualValue instanceof Set, 'anySet()') 85 | const isA: MatcherCreator = (clazz) => new Matcher((actualValue) => actualValue instanceof clazz, 'isA()') 86 | 87 | const arrayIncludes: MatcherCreator = (arrayVal) => 88 | new Matcher((actualValue) => Array.isArray(actualValue) && actualValue.includes(arrayVal), 'arrayIncludes()') 89 | const setHas: MatcherCreator, unknown> = (arrayVal) => 90 | new Matcher((actualValue) => anySet().asymmetricMatch(actualValue) && actualValue.has(arrayVal), 'setHas()') 91 | const mapHas: MatcherCreator, unknown> = (mapVal) => 92 | new Matcher((actualValue) => anyMap().asymmetricMatch(actualValue) && actualValue.has(mapVal), 'mapHas()') 93 | const objectContainsKey: MatcherCreator, string> = (key) => 94 | new Matcher((actualValue) => anyObject().asymmetricMatch(actualValue) && actualValue[key!] !== undefined, 'objectContainsKey()') 95 | const objectContainsValue: MatcherCreator | ArrayLike> = (value) => 96 | new Matcher( 97 | (actualValue) => anyObject().asymmetricMatch(actualValue) && Object.values(actualValue).includes(value), 98 | 'objectContainsValue()', 99 | ) 100 | 101 | const notNull: MatcherCreator = () => new Matcher((actualValue) => actualValue !== null, 'notNull()') 102 | const notUndefined: MatcherCreator = () => new Matcher((actualValue) => actualValue !== undefined, 'notUndefined()') 103 | const notEmpty: MatcherCreator = () => 104 | new Matcher((actualValue) => actualValue !== null && actualValue !== undefined && actualValue !== '', 'notEmpty()') 105 | 106 | const captor = () => new CaptorMatcher() 107 | const matches = (matcher: MatcherFn) => new Matcher(matcher, 'matches()') 108 | 109 | export { 110 | Matcher, 111 | CaptorMatcher, 112 | any, 113 | anyBoolean, 114 | anyNumber, 115 | anyString, 116 | anyFunction, 117 | anySymbol, 118 | anyObject, 119 | anyArray, 120 | anyMap, 121 | anySet, 122 | isA, 123 | arrayIncludes, 124 | setHas, 125 | mapHas, 126 | objectContainsKey, 127 | objectContainsValue, 128 | notNull, 129 | notUndefined, 130 | notEmpty, 131 | captor, 132 | matches, 133 | } 134 | export type { MatcherFn, MatchersOrLiterals, MatcherCreator, MatcherLike } 135 | -------------------------------------------------------------------------------- /src/Mock.ts: -------------------------------------------------------------------------------- 1 | import { calledWithFn } from './CalledWithFn' 2 | import { MatchersOrLiterals } from './Matchers' 3 | import { FallbackImplementation } from './types' 4 | import { DeepPartial } from 'ts-essentials' 5 | import { Mock, vi } from 'vitest' 6 | 7 | type ProxiedProperty = string | number | symbol 8 | 9 | interface GlobalConfig { 10 | // ignoreProps is required when we don't want to return anything for a mock (for example, when mocking a promise). 11 | ignoreProps?: ProxiedProperty[] 12 | } 13 | 14 | const DEFAULT_CONFIG: GlobalConfig = { 15 | ignoreProps: ['then'], 16 | } 17 | 18 | let GLOBAL_CONFIG = DEFAULT_CONFIG 19 | 20 | const VitestMockExtended = { 21 | DEFAULT_CONFIG, 22 | configure: (config: GlobalConfig) => { 23 | // Shallow merge so they can override anything they want. 24 | GLOBAL_CONFIG = { ...DEFAULT_CONFIG, ...config } 25 | }, 26 | resetConfig: () => { 27 | GLOBAL_CONFIG = DEFAULT_CONFIG 28 | }, 29 | } 30 | 31 | interface CalledWithMock extends Mock> { 32 | calledWith: (...args: Y | MatchersOrLiterals) => Mock> 33 | } 34 | 35 | type _MockProxy = { 36 | [K in keyof T]: T[K] extends (...args: infer A) => infer B ? T[K] & CalledWithMock : T[K] 37 | } 38 | 39 | type MockProxy = _MockProxy & T 40 | 41 | type _DeepMockProxy = { 42 | // This supports deep mocks in the else branch 43 | [K in keyof T]: T[K] extends (...args: infer A) => infer B ? T[K] & CalledWithMock : T[K] & _DeepMockProxy 44 | } 45 | 46 | // we intersect with T here instead of on the mapped type above to 47 | // prevent immediate type resolution on a recursive type, this will 48 | // help to improve performance for deeply nested recursive mocking 49 | // at the same time, this intersection preserves private properties 50 | type DeepMockProxy = _DeepMockProxy & T 51 | 52 | type _DeepMockProxyWithFuncPropSupport = { 53 | // This supports deep mocks in the else branch 54 | [K in keyof T]: T[K] extends (...args: infer A) => infer B ? CalledWithMock & DeepMockProxy : DeepMockProxy 55 | } 56 | 57 | type DeepMockProxyWithFuncPropSupport = _DeepMockProxyWithFuncPropSupport & T 58 | 59 | interface MockOpts { 60 | deep?: boolean 61 | useActualToJSON?: boolean 62 | fallbackMockImplementation?: (...args: any[]) => any 63 | } 64 | 65 | const mockClear = (mock: MockProxy) => { 66 | for (const key of Object.keys(mock)) { 67 | const value = mock[key] 68 | if (value === null || value === undefined) { 69 | continue 70 | } 71 | 72 | if (value._isMockObject) { 73 | mockClear(value) 74 | } 75 | 76 | if (value._isMockFunction && 'mockClear' in value) { 77 | value.mockClear() 78 | } 79 | } 80 | 81 | // This is a catch for if they pass in a vi.fn() 82 | if (!mock._isMockObject) { 83 | return mock.mockClear() 84 | } 85 | } 86 | 87 | const mockReset = (mock: MockProxy) => { 88 | for (const key of Object.keys(mock)) { 89 | if (mock[key] === null || mock[key] === undefined) { 90 | continue 91 | } 92 | 93 | if (mock[key]._isMockObject) { 94 | mockReset(mock[key]) 95 | } 96 | if (mock[key]._isMockFunction) { 97 | mock[key].mockReset() 98 | } 99 | } 100 | 101 | // This is a catch for if they pass in a vi.fn() 102 | // Worst case, we will create a vi.fn() (since this is a proxy) 103 | // below in the get and call mockReset on it 104 | if (!mock._isMockObject) { 105 | return mock.mockReset() 106 | } 107 | } 108 | 109 | function mockDeep( 110 | opts: { 111 | funcPropSupport?: true 112 | fallbackMockImplementation?: MockOpts['fallbackMockImplementation'] 113 | }, 114 | mockImplementation?: DeepPartial, 115 | ): DeepMockProxyWithFuncPropSupport 116 | function mockDeep(mockImplementation?: DeepPartial): DeepMockProxy 117 | function mockDeep(arg1: any, arg2?: any) { 118 | const [opts, mockImplementation] = 119 | typeof arg1 === 'object' 120 | && (typeof arg1.fallbackMockImplementation === 'function' || arg1.funcPropSupport === true) 121 | ? [arg1, arg2] 122 | : [{}, arg1] 123 | return mock(mockImplementation, { deep: true, fallbackMockImplementation: opts.fallbackMockImplementation }) 124 | } 125 | 126 | const overrideMockImp = (obj: DeepPartial, opts?: MockOpts) => { 127 | const proxy = new Proxy>(obj, handler(opts)) 128 | for (const name of Object.keys(obj)) { 129 | if (typeof obj[name] === 'object' && obj[name] !== null) { 130 | proxy[name] = overrideMockImp(obj[name], opts) 131 | } else { 132 | proxy[name] = obj[name] 133 | } 134 | } 135 | 136 | return proxy 137 | } 138 | 139 | const handler = (opts?: MockOpts) => ({ 140 | ownKeys(target: MockProxy) { 141 | return Reflect.ownKeys(target) 142 | }, 143 | 144 | set: (obj: MockProxy, property: ProxiedProperty, value: any) => { 145 | obj[property] = value 146 | return true 147 | }, 148 | 149 | get: (obj: MockProxy, property: ProxiedProperty) => { 150 | if (!(property in obj)) { 151 | if (property === '_isMockObject' || property === '_isMockFunction') { 152 | return undefined 153 | } 154 | 155 | if (GLOBAL_CONFIG.ignoreProps?.includes(property)) { 156 | return undefined 157 | } 158 | // Jest's internal equality checking does some wierd stuff to check for iterable equality 159 | if (property === Symbol.iterator) { 160 | return obj[property] 161 | } 162 | 163 | if (opts?.useActualToJSON && property === 'toJSON') { 164 | return JSON.stringify(obj) 165 | } 166 | 167 | // So this calls check here is totally not ideal - jest internally does a 168 | // check to see if this is a spy - which we want to say no to, but blindly returning 169 | // an proxy for calls results in the spy check returning true. This is another reason 170 | // why deep is opt in. 171 | const fn = calledWithFn({ fallbackMockImplementation: opts?.fallbackMockImplementation }) 172 | if (opts?.deep && property !== 'calls') { 173 | obj[property] = new Proxy>(fn, handler(opts)) 174 | obj[property]._isMockObject = true 175 | } else { 176 | obj[property] = fn 177 | } 178 | } 179 | 180 | // @ts-expect-error expected type mismatch due to any 181 | if (obj instanceof Date && typeof obj[property] === 'function') { 182 | // @ts-expect-error expected type mismatch due to any 183 | return obj[property].bind(obj) 184 | } 185 | 186 | return obj[property] 187 | }, 188 | }) 189 | 190 | const mock = & T = MockProxy & T>( 191 | mockImplementation: DeepPartial = {} as DeepPartial, 192 | opts?: MockOpts, 193 | ): MockedReturn => { 194 | // @ts-expect-error private 195 | mockImplementation!._isMockObject = true 196 | return overrideMockImp(mockImplementation, opts) 197 | } 198 | 199 | const mockFn = < 200 | T, 201 | A extends any[] = T extends (...args: infer AReal) => any ? AReal : any[], 202 | R = T extends (...args: any) => infer RReal ? RReal : any, 203 | >(): CalledWithMock & T => { 204 | // @ts-expect-error hard to get this type right using any 205 | return calledWithFn() 206 | } 207 | 208 | function mocked(obj: T, deep?: false): ReturnType> 209 | function mocked(obj: T, deep: true): ReturnType> 210 | function mocked(obj: T, _deep?: boolean) { 211 | return obj; 212 | } 213 | 214 | function mockedFn(obj: T) { 215 | return obj as ReturnType>; 216 | } 217 | 218 | const stub = (): T => { 219 | return new Proxy({} as T, { 220 | get: (obj, property: ProxiedProperty) => { 221 | if (property in obj) { 222 | // @ts-expect-error expected 223 | return obj[property] 224 | } 225 | return vi.fn() 226 | }, 227 | }) 228 | } 229 | 230 | export { mock, VitestMockExtended, mockClear, mockReset, mockDeep, mockFn, stub, mocked, mockedFn } 231 | export type { GlobalConfig, CalledWithMock, MockProxy, DeepMockProxy, MockOpts } 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vitest-mock-extended 2 | 3 | > Type safe mocking extensions for Vitest ✅ 4 | 5 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 6 | [![Tests](https://github.com/eratio08/vitest-mock-extended/actions/workflows/run-unit-tests.yml/badge.svg)](https://github.com/eratio08/vitest-mock-extended/actions/workflows/run-unit-tests.yml) 7 | [![npm downloads](https://badgen.net/npm/dw/vitest-mock-extended)](https://www.npmjs.com/package/vitest-mock-extended) 8 | 9 | THIS IS A FORK OF [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) ALL CREDITS GO TO THE ORIGINAL AUTHOR 10 | 11 | ## Features 12 | 13 | - Provides complete Typescript type safety for interfaces, argument types and return types 14 | - Ability to mock any interface or object 15 | - calledWith() extension to provide argument specific expectations, which works for objects and functions. 16 | - Extensive Matcher API compatible with Jasmine matchers 17 | - Supports mocking deep objects / class instances. 18 | - Familiar Jest like API 19 | 20 | ## Installation 21 | 22 | ```bash 23 | npm install vitest-mock-extended --save-dev 24 | ``` 25 | 26 | or 27 | 28 | ```bash 29 | yarn add vitest-mock-extended --dev 30 | ``` 31 | 32 | If `ReferenceError: vi is not defined` related error occurs, please set [`globals: true`](https://vitest.dev/config/#globals). 33 | 34 | ## Example 35 | 36 | ```ts 37 | import { mock } from 'vitest-mock-extended'; 38 | 39 | interface PartyProvider { 40 | getPartyType: () => string; 41 | getSongs: (type: string) => string[]; 42 | start: (type: string) => void; 43 | } 44 | 45 | describe('Party Tests', () => { 46 | test('Mock out an interface', () => { 47 | const mock = mock(); 48 | mock.start('disco party'); 49 | 50 | expect(mock.start).toHaveBeenCalledWith('disco party'); 51 | }); 52 | 53 | test('mock out a return type', () => { 54 | const mock = mock(); 55 | mock.getPartyType.mockReturnValue('west coast party'); 56 | 57 | expect(mock.getPartyType()).toBe('west coast party'); 58 | }); 59 | 60 | test('Can specify fallbackMockImplementation', () => { 61 | const mockObj = mock( 62 | {}, 63 | { 64 | fallbackMockImplementation: () => { 65 | throw new Error('not mocked'); 66 | }, 67 | } 68 | ); 69 | 70 | expect(() => mockObj.getSomethingWithArgs(1, 2)).toThrowError('not mocked'); 71 | }); 72 | }); 73 | ``` 74 | 75 | ## Assigning Mocks with a Type 76 | 77 | If you wish to assign a mock to a variable that requires a type in your test, then you should use the MockProxy<> type 78 | given that this will provide the apis for calledWith() and other built-in vitest types for providing test functionality. 79 | 80 | ```ts 81 | import { MockProxy, mock } from 'vitest-mock-extended'; 82 | 83 | describe('test', () => { 84 | let myMock: MockProxy; 85 | 86 | beforeEach(() => { 87 | myMock = mock(); 88 | }) 89 | 90 | test(() => { 91 | myMock.calledWith(1).mockReturnValue(2); 92 | ... 93 | }) 94 | }); 95 | 96 | ``` 97 | 98 | ## calledWith() Extension 99 | 100 | `vitest-mock-extended` allows for invocation matching expectations. Types of arguments, even when using matchers are type checked. 101 | 102 | ```ts 103 | const provider = mock(); 104 | provider.getSongs.calledWith('disco party').mockReturnValue(['Dance the night away', 'Stayin Alive']); 105 | expect(provider.getSongs('disco party')).toEqual(['Dance the night away', 'Stayin Alive']); 106 | 107 | // Matchers 108 | provider.getSongs.calledWith(any()).mockReturnValue(['Saw her standing there']); 109 | provider.getSongs.calledWith(anyString()).mockReturnValue(['Saw her standing there']); 110 | ``` 111 | 112 | You can also use `mockFn()` to create a `vi.fn()` with the calledWith extension: 113 | 114 | ```ts 115 | type MyFn = (x: number, y: number) => Promise; 116 | const fn = mockFn(); 117 | fn.calledWith(1, 2).mockReturnValue('str'); 118 | ``` 119 | 120 | ## Clearing / Resetting Mocks 121 | 122 | `vitest-mock-extended` exposes a mockClear and mockReset for resetting or clearing mocks with the same 123 | functionality as `vi.fn()`. 124 | 125 | ```ts 126 | import { mock, mockClear, mockReset } from 'vitest-mock-extended'; 127 | 128 | describe('test', () => { 129 | const mock: UserService = mock(); 130 | 131 | beforeEach(() => { 132 | mockReset(mock); // or mockClear(mock) 133 | }); 134 | ... 135 | }) 136 | ``` 137 | 138 | ## Deep mocks 139 | 140 | If your class has objects returns from methods that you would also like to mock, you can use `mockDeep` in 141 | replacement for mock. 142 | 143 | ```ts 144 | import { mockDeep } from 'vitest-mock-extended'; 145 | 146 | const mockObj: DeepMockProxy = mockDeep(); 147 | mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4); 148 | expect(mockObj.deepProp.getNumber(1)).toBe(4); 149 | ``` 150 | 151 | if you also need support for properties on functions, you can pass in an option to enable this 152 | 153 | ```ts 154 | import { mockDeep } from 'vitest-mock-extended'; 155 | const mockObj: DeepMockProxy = mockDeep({ funcPropSupport: true }); 156 | mockObj.deepProp.calledWith(1).mockReturnValue(3); 157 | mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4); 158 | expect(mockObj.deepProp(1)).toBe(3); 159 | expect(mockObj.deepProp.getNumber(1)).toBe(4); 160 | ``` 161 | 162 | You can also provide a fallback mock implementation to be used if you do not define a return value using `calledWith`. 163 | 164 | ```ts 165 | import { mockDeep } from 'jest-mock-extended'; 166 | const mockObj = mockDeep({ 167 | fallbackMockImplementation: () => { 168 | throw new Error('please add expected return value using calledWith'); 169 | }, 170 | }); 171 | expect(() => mockObj.getNumber()).toThrowError('not mocked'); 172 | ``` 173 | 174 | ## Mocked Type Helpers 175 | If you mock objects/functions of modules and can't refer them directly due to hoist, 176 | mocked type helpers can be used. This is similar to the use case of Vitest's `vi.mocked` 177 | ```ts 178 | // APIs 179 | import { mocked, mockedFn } from "vitest-mock-extended"; 180 | import { originalObj, originalFn} from "somewhere"; 181 | 182 | const mockedObj = mocked(originalObj); 183 | const deepMockedObj = mocked(originalObj, true); 184 | const mockedFunction = mockedFn(originalFn); 185 | ``` 186 | 187 | An example would be 188 | ```ts 189 | // Mock a module 190 | // @/libs/example.mock.ts 191 | import { mock } from "vitest-mock-extended"; 192 | import { ExampleClient } from "@/libs/example"; 193 | 194 | vi.mock(import("@/libs/example"), async (importOriginal) => { 195 | const actual = await importOriginal(); 196 | return { 197 | ...actual, 198 | // Due to vi.mock being hoisted, we have to mock here directly instead of 199 | // defining an exampleMock outside and assign it to example 200 | example: mock(), 201 | }; 202 | }); 203 | 204 | // Use the mocked object 205 | import "@/libs/example.mock"; // Mock out the actual client 206 | import { mocked } from "vitest-mock-extended"; 207 | import { example } from "@/libs/example"; 208 | 209 | const exampleMock = mocked(example); 210 | 211 | test("send notification", () => { 212 | example.function.mockResolvedValue(xxx); 213 | ... 214 | } 215 | ``` 216 | 217 | ## Available Matchers 218 | 219 | | Matcher | Description | 220 | | ---------------------- | ---------------------------------------------------------- | 221 | | any() | Matches any arg of any type. | 222 | | anyBoolean() | Matches any boolean (true or false) | 223 | | anyString() | Matches any string including empty string | 224 | | anyNumber() | Matches any number that is not NaN | 225 | | anyFunction() | Matches any function | 226 | | anyObject() | Matches any object (typeof m === 'object') and is not null | 227 | | anyArray() | Matches any array | 228 | | anyMap() | Matches any Map | 229 | | anySet() | Matches any Set | 230 | | isA(class) | e.g isA(DiscoPartyProvider) | 231 | | includes('value') | Checks if value is in the argument array | 232 | | containsKey('key') | Checks if the key exists in the object | 233 | | containsValue('value') | Checks if the value exists in an object | 234 | | has('value') | checks if the value exists in a Set | 235 | | notNull() | value !== null | 236 | | notUndefined() | value !== undefined | 237 | | notEmpty() | value !== undefined && value !== null && value !== '' | 238 | | captor() | Used to capture an arg - alternative to mock.calls[0][0] | 239 | 240 | ## Writing a Custom Matcher 241 | 242 | Custom matchers can be written using a `MatcherCreator` 243 | 244 | ```ts 245 | import { MatcherCreator, Matcher } from 'vitest-mock-extended'; 246 | 247 | // expectedValue is optional 248 | export const myMatcher: MatcherCreator = (expectedValue) => 249 | new Matcher((actualValue) => { 250 | return expectedValue === actualValue && actualValue.isSpecial; 251 | }); 252 | ``` 253 | 254 | By default, the expected value and actual value are the same type. In the case where you need to type the expected value 255 | differently than the actual value, you can use the optional 2 generic parameter: 256 | 257 | ```ts 258 | import { MatcherCreator, Matcher } from 'vitest-mock-extended'; 259 | 260 | // expectedValue is optional 261 | export const myMatcher: MatcherCreator = (expectedValue) => 262 | new Matcher((actualValue) => { 263 | return actualValue.includes(expectedValue); 264 | }); 265 | ``` 266 | -------------------------------------------------------------------------------- /src/Matchers.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | any, 3 | anyArray, 4 | anyBoolean, 5 | anyNumber, 6 | anyObject, 7 | anyString, 8 | anyMap, 9 | anySet, 10 | isA, 11 | arrayIncludes, 12 | anyFunction, 13 | anySymbol, 14 | setHas, 15 | mapHas, 16 | objectContainsKey, 17 | objectContainsValue, 18 | notNull, 19 | notUndefined, 20 | notEmpty, 21 | captor, 22 | matches, 23 | } from './Matchers' 24 | import { beforeEach, vi, describe, test, expect } from 'vitest' 25 | import { mock } from './Mock' 26 | 27 | class Cls { } 28 | 29 | describe('Matchers', () => { 30 | describe('any', () => { 31 | test('returns true for false', () => { 32 | expect(any().asymmetricMatch(false)).toBe(true) 33 | }) 34 | 35 | test('returns true for undefined', () => { 36 | expect(any().asymmetricMatch(undefined)).toBe(true) 37 | }) 38 | 39 | test('returns true for null', () => { 40 | expect(any().asymmetricMatch(null)).toBe(true) 41 | }) 42 | 43 | // test('Supports undefined in chain', () => { 44 | // const f = vi.fn(); 45 | // f(undefined); 46 | 47 | // // @ts-ignore 48 | // console.info(f.mock); 49 | 50 | // expect(f).toHaveBeenCalledWith(any()); 51 | // }); 52 | }) 53 | 54 | describe('anyString', () => { 55 | test('returns true for empty string', () => { 56 | expect(anyString().asymmetricMatch('')).toBe(true) 57 | }) 58 | 59 | test('returns true for non-empty string', () => { 60 | expect(anyString().asymmetricMatch('123')).toBe(true) 61 | }) 62 | 63 | test('returns false for number', () => { 64 | // @ts-expect-error deliberate type mismatch 65 | expect(anyString().asymmetricMatch(123)).toBe(false) 66 | }) 67 | 68 | test('returns false for null', () => { 69 | // @ts-expect-error deliberate type mismatch 70 | expect(anyString().asymmetricMatch(null)).toBe(false) 71 | }) 72 | 73 | test('returns false for undefined', () => { 74 | // @ts-expect-error deliberate type mismatch 75 | expect(anyString().asymmetricMatch(undefined)).toBe(false) 76 | }) 77 | }) 78 | 79 | describe('anyNumber', () => { 80 | test('returns true for 0', () => { 81 | expect(anyNumber().asymmetricMatch(0)).toBe(true) 82 | }) 83 | 84 | test('returns true for normal number', () => { 85 | expect(anyNumber().asymmetricMatch(123)).toBe(true) 86 | }) 87 | 88 | test('returns false for string', () => { 89 | // @ts-expect-error deliberate type mismatch 90 | expect(anyNumber().asymmetricMatch('123')).toBe(false) 91 | }) 92 | 93 | test('returns false for null', () => { 94 | // @ts-expect-error deliberate type mismatch 95 | expect(anyNumber().asymmetricMatch(null)).toBe(false) 96 | }) 97 | 98 | test('returns false for undefined', () => { 99 | // @ts-expect-error deliberate type mismatch 100 | expect(anyNumber().asymmetricMatch(undefined)).toBe(false) 101 | }) 102 | 103 | test('returns false for NaN', () => { 104 | expect(anyNumber().asymmetricMatch(NaN)).toBe(false) 105 | }) 106 | }) 107 | 108 | describe('anyBoolean', () => { 109 | test('returns true for true', () => { 110 | expect(anyBoolean().asymmetricMatch(true)).toBe(true) 111 | }) 112 | 113 | test('returns true for false', () => { 114 | expect(anyBoolean().asymmetricMatch(false)).toBe(true) 115 | }) 116 | 117 | test('returns false for string', () => { 118 | // @ts-expect-error deliberate type mismatch 119 | expect(anyBoolean().asymmetricMatch('true')).toBe(false) 120 | }) 121 | 122 | test('returns false for null', () => { 123 | // @ts-expect-error deliberate type mismatch 124 | expect(anyBoolean().asymmetricMatch(null)).toBe(false) 125 | }) 126 | 127 | test('returns false for undefined', () => { 128 | // @ts-expect-error deliberate type mismatch 129 | expect(anyBoolean().asymmetricMatch(undefined)).toBe(false) 130 | }) 131 | }) 132 | 133 | describe('anyFunction', () => { 134 | test('returns true for function', () => { 135 | expect(anyFunction().asymmetricMatch(() => { })).toBe(true) 136 | }) 137 | 138 | test('returns false for string', () => { 139 | // @ts-expect-error deliberate type mismatch 140 | expect(anyFunction().asymmetricMatch('true')).toBe(false) 141 | }) 142 | 143 | test('returns false for null', () => { 144 | // @ts-expect-error deliberate type mismatch 145 | expect(anyFunction().asymmetricMatch(null)).toBe(false) 146 | }) 147 | 148 | test('returns false for undefined', () => { 149 | // @ts-expect-error deliberate type mismatch 150 | expect(anyFunction().asymmetricMatch(undefined)).toBe(false) 151 | }) 152 | }) 153 | 154 | describe('anySymbol', () => { 155 | test('returns true for symbol', () => { 156 | expect(anySymbol().asymmetricMatch(Symbol('123'))).toBe(true) 157 | }) 158 | 159 | test('returns false for string', () => { 160 | // @ts-expect-error deliberate type mismatch 161 | expect(anySymbol().asymmetricMatch('123')).toBe(false) 162 | }) 163 | 164 | test('returns false for null', () => { 165 | // @ts-expect-error deliberate type mismatch 166 | expect(anySymbol().asymmetricMatch(null)).toBe(false) 167 | }) 168 | 169 | test('returns false for undefined', () => { 170 | // @ts-expect-error deliberate type mismatch 171 | expect(anySymbol().asymmetricMatch(undefined)).toBe(false) 172 | }) 173 | }) 174 | 175 | describe('anyObject', () => { 176 | test('returns true for object', () => { 177 | expect(anyObject().asymmetricMatch({})).toBe(true) 178 | }) 179 | 180 | test('returns true for new object', () => { 181 | expect(anyObject().asymmetricMatch(new Object())).toBe(true) 182 | }) 183 | 184 | test('returns true for new instance', () => { 185 | expect(anyObject().asymmetricMatch(new Cls())).toBe(true) 186 | }) 187 | 188 | test('returns true for new builtin', () => { 189 | expect(anyObject().asymmetricMatch(new Map())).toBe(true) 190 | }) 191 | 192 | test('returns false for string', () => { 193 | expect(anyObject().asymmetricMatch('123')).toBe(false) 194 | }) 195 | 196 | test('returns false for number', () => { 197 | expect(anyObject().asymmetricMatch(123)).toBe(false) 198 | }) 199 | 200 | test('returns false for null', () => { 201 | expect(anyObject().asymmetricMatch(null)).toBe(false) 202 | }) 203 | 204 | test('returns false for undefined', () => { 205 | expect(anyObject().asymmetricMatch(undefined)).toBe(false) 206 | }) 207 | }) 208 | 209 | describe('anyArray', () => { 210 | test('returns true for empty array', () => { 211 | expect(anyArray().asymmetricMatch([])).toBe(true) 212 | }) 213 | 214 | test('returns true for non empty', () => { 215 | expect(anyArray().asymmetricMatch([1, 2, 3])).toBe(true) 216 | }) 217 | 218 | test('returns false for object', () => { 219 | // @ts-expect-error deliberate type mismatch 220 | expect(anyArray().asymmetricMatch({})).toBe(false) 221 | }) 222 | 223 | test('returns false for null', () => { 224 | // @ts-expect-error deliberate type mismatch 225 | expect(anyArray().asymmetricMatch(null)).toBe(false) 226 | }) 227 | 228 | test('returns false for undefined', () => { 229 | // @ts-expect-error deliberate type mismatch 230 | expect(anyArray().asymmetricMatch(undefined)).toBe(false) 231 | }) 232 | }) 233 | 234 | describe('anyMap', () => { 235 | test('returns true for empty Map', () => { 236 | expect(anyMap().asymmetricMatch(new Map())).toBe(true) 237 | }) 238 | 239 | test('returns true for non empty', () => { 240 | const map = new Map() 241 | map.set(1, 2) 242 | expect(anyMap().asymmetricMatch(map)).toBe(true) 243 | }) 244 | 245 | test('returns false for object', () => { 246 | // @ts-expect-error deliberate type mismatch 247 | expect(anyMap().asymmetricMatch({})).toBe(false) 248 | }) 249 | 250 | test('returns false for null', () => { 251 | // @ts-expect-error deliberate type mismatch 252 | expect(anyMap().asymmetricMatch(null)).toBe(false) 253 | }) 254 | 255 | test('returns false for undefined', () => { 256 | // @ts-expect-error deliberate type mismatch 257 | expect(anyMap().asymmetricMatch(undefined)).toBe(false) 258 | }) 259 | }) 260 | 261 | describe('anySet', () => { 262 | test('returns true for empty Set', () => { 263 | expect(anySet().asymmetricMatch(new Set())).toBe(true) 264 | }) 265 | 266 | test('returns true for non empty', () => { 267 | const set = new Set() 268 | set.add(2) 269 | expect(anySet().asymmetricMatch(set)).toBe(true) 270 | }) 271 | 272 | test('returns false for object', () => { 273 | // @ts-expect-error deliberate type mismatch 274 | expect(anySet().asymmetricMatch({})).toBe(false) 275 | }) 276 | 277 | test('returns false for null', () => { 278 | // @ts-expect-error deliberate type mismatch 279 | expect(anySet().asymmetricMatch(null)).toBe(false) 280 | }) 281 | 282 | test('returns false for undefined', () => { 283 | // @ts-expect-error deliberate type mismatch 284 | expect(anySet().asymmetricMatch(undefined)).toBe(false) 285 | }) 286 | }) 287 | 288 | describe('isA', () => { 289 | test('returns true when class is the same builtin', () => { 290 | expect(isA(Map).asymmetricMatch(new Map())).toBe(true) 291 | }) 292 | 293 | test('returns true for non empty', () => { 294 | expect(isA(Cls).asymmetricMatch(new Cls())).toBe(true) 295 | }) 296 | 297 | test('returns false for object', () => { 298 | expect(isA(Cls).asymmetricMatch({})).toBe(false) 299 | }) 300 | 301 | test('returns false for null', () => { 302 | expect(isA(Cls).asymmetricMatch(null)).toBe(false) 303 | }) 304 | 305 | test('returns false for undefined', () => { 306 | expect(isA(Cls).asymmetricMatch(undefined)).toBe(false) 307 | }) 308 | }) 309 | 310 | describe('arrayIncludes', () => { 311 | test('returns true when array contains value', () => { 312 | expect(arrayIncludes('val').asymmetricMatch(['val', 'val2'])).toBe(true) 313 | }) 314 | 315 | test('returns false when array does not contain value', () => { 316 | expect(arrayIncludes('val3').asymmetricMatch(['val', 'val2'])).toBe(false) 317 | }) 318 | 319 | test('returns false when not a map', () => { 320 | // @ts-expect-error deliberate type mismatch 321 | expect(arrayIncludes('val3').asymmetricMatch({})).toBe(false) 322 | }) 323 | 324 | test('returns false when for null', () => { 325 | // @ts-expect-error deliberate type mismatch 326 | expect(arrayIncludes('val3').asymmetricMatch(null)).toBe(false) 327 | }) 328 | 329 | test('returns false when for undefined', () => { 330 | // @ts-expect-error deliberate type mismatch 331 | expect(arrayIncludes('val3').asymmetricMatch(undefined)).toBe(false) 332 | }) 333 | }) 334 | 335 | describe('mapHas', () => { 336 | test('returns true when map contains key', () => { 337 | expect(mapHas('key').asymmetricMatch(new Map([['key', 'val']]))).toBe(true) 338 | }) 339 | 340 | test('returns false when map does not contain key', () => { 341 | expect(mapHas('key3').asymmetricMatch(new Map([['key', 'val']]))).toBe(false) 342 | }) 343 | 344 | test('returns false when not a map', () => { 345 | // @ts-expect-error deliberate type mismatch 346 | expect(mapHas('val3').asymmetricMatch({})).toBe(false) 347 | }) 348 | 349 | test('returns false when for null', () => { 350 | // @ts-expect-error deliberate type mismatch 351 | expect(mapHas('val3').asymmetricMatch(null)).toBe(false) 352 | }) 353 | 354 | test('returns false when for undefined', () => { 355 | // @ts-expect-error deliberate type mismatch 356 | expect(mapHas('val3').asymmetricMatch(undefined)).toBe(false) 357 | }) 358 | }) 359 | 360 | describe('setHas', () => { 361 | test('returns true when set contains value', () => { 362 | expect(setHas('val').asymmetricMatch(new Set(['val']))).toBe(true) 363 | }) 364 | 365 | test('returns false when set does not contain value', () => { 366 | expect(setHas('val3').asymmetricMatch(new Set(['val', 'val2']))).toBe(false) 367 | }) 368 | 369 | test('returns false when not a set', () => { 370 | // @ts-expect-error deliberate type mismatch 371 | expect(setHas('val3').asymmetricMatch({})).toBe(false) 372 | }) 373 | 374 | test('returns false when for null', () => { 375 | // @ts-expect-error deliberate type mismatch 376 | expect(setHas('val3').asymmetricMatch(null)).toBe(false) 377 | }) 378 | 379 | test('returns false when for undefined', () => { 380 | // @ts-expect-error deliberate type mismatch 381 | expect(setHas('val3').asymmetricMatch(undefined)).toBe(false) 382 | }) 383 | }) 384 | 385 | describe('objectContainsKey', () => { 386 | test('returns true when object contains key', () => { 387 | expect(objectContainsKey('key').asymmetricMatch({ key: 'val' })).toBe(true) 388 | }) 389 | 390 | test('returns false when object does not contain key', () => { 391 | expect(objectContainsKey('key3').asymmetricMatch({ key: 'val' })).toBe(false) 392 | }) 393 | 394 | test('returns false when not a object', () => { 395 | // @ts-expect-error deliberate type mismatch 396 | expect(objectContainsKey('val3').asymmetricMatch(213)).toBe(false) 397 | }) 398 | 399 | test('returns false when for null', () => { 400 | // @ts-expect-error deliberate type mismatch 401 | expect(objectContainsKey('val3').asymmetricMatch(null)).toBe(false) 402 | }) 403 | 404 | test('returns false when for undefined', () => { 405 | // @ts-expect-error deliberate type mismatch 406 | expect(objectContainsKey('val3').asymmetricMatch(undefined)).toBe(false) 407 | }) 408 | }) 409 | 410 | describe('objectContainsValue', () => { 411 | test('returns true when object contains value', () => { 412 | expect(objectContainsValue('val').asymmetricMatch({ key: 'val' })).toBe(true) 413 | }) 414 | 415 | test('returns false when object does not contain value', () => { 416 | expect(objectContainsValue('val3').asymmetricMatch({ key: 'val' })).toBe(false) 417 | }) 418 | 419 | test('returns false when not a object', () => { 420 | // @ts-expect-error deliberate type mismatch 421 | expect(objectContainsValue('val3').asymmetricMatch(213)).toBe(false) 422 | }) 423 | 424 | test('returns false when for null', () => { 425 | // @ts-expect-error deliberate type mismatch 426 | expect(objectContainsValue('val3').asymmetricMatch(null)).toBe(false) 427 | }) 428 | 429 | test('returns false when for undefined', () => { 430 | // @ts-expect-error deliberate type mismatch 431 | expect(objectContainsValue('val3').asymmetricMatch(undefined)).toBe(false) 432 | }) 433 | }) 434 | 435 | describe('notNull', () => { 436 | test('returns true when object', () => { 437 | expect(notNull().asymmetricMatch({ key: 'val' })).toBe(true) 438 | }) 439 | 440 | test('returns true when undefined', () => { 441 | expect(notNull().asymmetricMatch(undefined)).toBe(true) 442 | }) 443 | 444 | test('returns true when empty string', () => { 445 | expect(notNull().asymmetricMatch('')).toBe(true) 446 | }) 447 | 448 | test('returns false when for null', () => { 449 | expect(notNull().asymmetricMatch(null)).toBe(false) 450 | }) 451 | }) 452 | 453 | describe('notUndefined', () => { 454 | test('returns true when object', () => { 455 | expect(notUndefined().asymmetricMatch({ key: 'val' })).toBe(true) 456 | }) 457 | 458 | test('returns true when null', () => { 459 | expect(notUndefined().asymmetricMatch(null)).toBe(true) 460 | }) 461 | 462 | test('returns true when empty string', () => { 463 | expect(notUndefined().asymmetricMatch('')).toBe(true) 464 | }) 465 | 466 | test('returns false when for undefined', () => { 467 | expect(notUndefined().asymmetricMatch(undefined)).toBe(false) 468 | }) 469 | }) 470 | 471 | describe('notEmpty', () => { 472 | test('returns true when object', () => { 473 | expect(notEmpty().asymmetricMatch({ key: 'val' })).toBe(true) 474 | }) 475 | 476 | test('returns true when null', () => { 477 | expect(notEmpty().asymmetricMatch(null)).toBe(false) 478 | }) 479 | 480 | test('returns true when empty string', () => { 481 | expect(notEmpty().asymmetricMatch('')).toBe(false) 482 | }) 483 | 484 | test('returns false when for undefined', () => { 485 | expect(notEmpty().asymmetricMatch(undefined)).toBe(false) 486 | }) 487 | }) 488 | 489 | describe('captor', () => { 490 | let fn: () => void 491 | let doSomething: (...args: any[]) => void 492 | 493 | beforeEach(() => { 494 | fn = vi.fn() 495 | doSomething = (fn: (...args: any[]) => void, count: number) => { 496 | fn(String(count), count, { 1: 2 }) 497 | } 498 | }) 499 | 500 | test('can capture arg with other matchers', () => { 501 | doSomething(fn, 1) 502 | 503 | const argCaptor = captor() 504 | expect(fn).toHaveBeenCalledWith(argCaptor, any(), any()) 505 | expect(argCaptor.value).toBe('1') 506 | }) 507 | 508 | test('stores all values', () => { 509 | doSomething(fn, 1) 510 | doSomething(fn, 2) 511 | doSomething(fn, 3) 512 | 513 | const argCaptor = captor() 514 | expect(fn).toHaveBeenNthCalledWith(1, argCaptor, any(), any()) 515 | expect(fn).toHaveBeenNthCalledWith(2, argCaptor, any(), any()) 516 | expect(fn).toHaveBeenNthCalledWith(3, argCaptor, any(), any()) 517 | 518 | expect(argCaptor.value).toBe('3') 519 | expect(argCaptor.values).toEqual(['1', '2', '3']) 520 | }) 521 | 522 | test('should allow captor as argument to calledWith', () => { 523 | //given 524 | interface MockInt { 525 | getNumber: (n: number) => number 526 | } 527 | const mockObj = mock() 528 | const argCaptor = captor() 529 | mockObj.getNumber.calledWith(argCaptor).mockReturnValue(1) 530 | 531 | //when 532 | const result = mockObj.getNumber(2) 533 | expect(result).toBe(1) 534 | expect(argCaptor.value).toBe(2) 535 | }) 536 | }) 537 | 538 | describe('matches function', () => { 539 | test('expects passes for when it returns true', () => { 540 | const fn = vi.fn() 541 | fn(1) 542 | 543 | expect(fn).toHaveBeenCalledWith(matches((val) => val === 1)) 544 | }) 545 | 546 | test('expects with not passes for when it returns false', () => { 547 | const fn = vi.fn() 548 | fn(1) 549 | 550 | expect(fn).not.toHaveBeenCalledWith(matches((val) => val === 2)) 551 | }) 552 | }) 553 | }) 554 | -------------------------------------------------------------------------------- /src/Mock.spec.ts: -------------------------------------------------------------------------------- 1 | import { mock, mockClear, mockDeep, mockReset, mockFn, VitestMockExtended, mocked, mockedFn } from './Mock' 2 | import { anyNumber } from './Matchers' 3 | import { calledWithFn } from './CalledWithFn' 4 | import { MockProxy } from './Mock' 5 | import { expect, vi, describe, test, it } from 'vitest' 6 | 7 | interface MockInt { 8 | id: number 9 | someValue?: boolean | null 10 | getNumber: () => number 11 | getNumberWithMockArg: (mock: unknown) => number 12 | getSomethingWithArgs: (arg1: number, arg2: number) => number 13 | getSomethingWithMoreArgs: (arg1: number, arg2: number, arg3: number) => number 14 | } 15 | 16 | class Test1 implements MockInt { 17 | readonly id: number 18 | public deepProp: Test2 = new Test2() 19 | private readonly anotherPart: number 20 | 21 | constructor(id: number) { 22 | this.id = id 23 | this.anotherPart = id 24 | } 25 | 26 | public ofAnother(test: Test1) { 27 | return test.getNumber() 28 | } 29 | 30 | public getNumber() { 31 | return this.id 32 | } 33 | 34 | public getNumberWithMockArg(_mock: unknown) { 35 | return this.id 36 | } 37 | 38 | public getSomethingWithArgs(arg1: number, arg2: number) { 39 | return this.id 40 | } 41 | 42 | public getSomethingWithMoreArgs(arg1: number, arg2: number, arg3: number) { 43 | return this.id 44 | } 45 | } 46 | 47 | class Test2 { 48 | public deeperProp: Test3 = new Test3() 49 | 50 | getNumber(num: number) { 51 | return num * 2 52 | } 53 | 54 | getAnotherString(str: string) { 55 | return `${str} another string` 56 | } 57 | } 58 | 59 | class Test3 { 60 | getNumber(num: number) { 61 | return num ^ 2 62 | } 63 | } 64 | class Test4 { 65 | constructor(_test1: Test1, _int: MockInt) { } 66 | } 67 | 68 | export interface FunctionWithPropsMockInt { 69 | (arg1: number): number 70 | 71 | prop: number 72 | 73 | nonDeepProp: (arg: Test1) => number 74 | 75 | deepProp: Test2 76 | } 77 | 78 | export class Test6 { 79 | public id: number 80 | funcValueProp: FunctionWithPropsMockInt 81 | 82 | constructor(funcValueProp: FunctionWithPropsMockInt, id: number) { 83 | this.id = id 84 | this.funcValueProp = funcValueProp 85 | } 86 | } 87 | 88 | describe('vitest-mock-extended', () => { 89 | test('Can be assigned back to itself even when there are private parts', () => { 90 | // No TS errors here 91 | const mockObj: Test1 = mock() 92 | // No error here. 93 | new Test1(1).ofAnother(mockObj) 94 | expect(mockObj.getNumber).toHaveBeenCalledTimes(1) 95 | }) 96 | 97 | test('Check that a vi.fn() is created without any invocation to the mock method', () => { 98 | const mockObj = mock() 99 | expect(mockObj.getNumber).toHaveBeenCalledTimes(0) 100 | }) 101 | 102 | test('Check that invocations are registered', () => { 103 | const mockObj: MockInt = mock() 104 | mockObj.getNumber() 105 | mockObj.getNumber() 106 | expect(mockObj.getNumber).toHaveBeenCalledTimes(2) 107 | }) 108 | 109 | test('Can mock a return value', () => { 110 | const mockObj = mock() 111 | mockObj.getNumber.mockReturnValue(12) 112 | expect(mockObj.getNumber()).toBe(12) 113 | }) 114 | 115 | test('Can specify args', () => { 116 | const mockObj = mock() 117 | mockObj.getSomethingWithArgs(1, 2) 118 | expect(mockObj.getSomethingWithArgs).toBeCalledWith(1, 2) 119 | }) 120 | 121 | test('Can mock implementation of method', () => { 122 | const mockObj = mock() 123 | mockObj.getSomethingWithArgs.mockImplementation((arg1, arg2) => { 124 | return arg1 + arg2 125 | }) 126 | 127 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 128 | }) 129 | 130 | test('Can specify calledWith', () => { 131 | const mockObj = mock() 132 | mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(1) 133 | 134 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(1) 135 | }) 136 | 137 | test('Can specify multiple calledWith', () => { 138 | const mockObj = mock() 139 | mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(3) 140 | mockObj.getSomethingWithArgs.calledWith(6, 7).mockReturnValue(13) 141 | 142 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 143 | expect(mockObj.getSomethingWithArgs(6, 7)).toBe(13) 144 | }) 145 | 146 | test('Can specify fallbackMockImplementation', () => { 147 | const mockObj = mock( 148 | {}, 149 | { 150 | fallbackMockImplementation: () => { 151 | throw new Error('not mocked') 152 | }, 153 | }, 154 | ) 155 | 156 | expect(() => mockObj.getSomethingWithArgs(1, 2)).toThrowError('not mocked') 157 | }) 158 | 159 | test('Can set props', () => { 160 | const mockObj = mock() 161 | mockObj.id = 17 162 | 163 | expect(mockObj.id).toBe(17) 164 | }) 165 | 166 | test('Can set false and null boolean props', () => { 167 | const mockObj = mock({ 168 | someValue: false, 169 | }) 170 | 171 | const mockObj2 = mock({ 172 | someValue: null, 173 | }) 174 | 175 | expect(mockObj.someValue).toBe(false) 176 | expect(mockObj2.someValue).toBe(null) 177 | }) 178 | 179 | test('can set undefined explicitly', () => { 180 | const mockObj = mock({ 181 | someValue: undefined, // this is intentionally set to undefined 182 | }) 183 | 184 | expect(mockObj.someValue).toBe(undefined) 185 | }) 186 | 187 | test('Equals self', () => { 188 | const mockObj = mock() 189 | expect(mockObj).toBe(mockObj) 190 | expect(mockObj).toEqual(mockObj) 191 | 192 | const spy = vi.fn() 193 | spy(mockObj) 194 | expect(spy).toHaveBeenCalledWith(mockObj) 195 | }) 196 | 197 | describe('Mimic Type', () => { 198 | test('can use MockProxy in place of Mock Type', () => { 199 | const t1: MockProxy = mock() 200 | const i1: MockProxy = mock() 201 | 202 | // no TS error 203 | const f = new Test4(t1, i1) 204 | }) 205 | }) 206 | 207 | describe('calledWith', () => { 208 | test('can use calledWith without mock', () => { 209 | const mockFunc = calledWithFn() 210 | mockFunc.calledWith(anyNumber(), anyNumber()).mockReturnValue(3) 211 | expect(mockFunc(1, 2)).toBe(3) 212 | }) 213 | 214 | test('Can specify matchers', () => { 215 | const mockObj = mock() 216 | mockObj.getSomethingWithArgs.calledWith(anyNumber(), anyNumber()).mockReturnValue(3) 217 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 218 | }) 219 | 220 | test('does not match when one arg does not match Matcher', () => { 221 | const mockObj = mock() 222 | mockObj.getSomethingWithArgs.calledWith(anyNumber(), anyNumber()).mockReturnValue(3) 223 | // @ts-expect-error deliberate type mismatch 224 | expect(mockObj.getSomethingWithArgs('1', 2)).toBe(undefined) 225 | }) 226 | 227 | test('can use literals', () => { 228 | const mockObj = mock() 229 | mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(3) 230 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 231 | }) 232 | 233 | test('can mix Matchers with literals', () => { 234 | const mockObj = mock() 235 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 236 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 237 | }) 238 | 239 | test('supports multiple calledWith', () => { 240 | const mockObj = mock() 241 | mockObj.getSomethingWithArgs.calledWith(2, anyNumber()).mockReturnValue(4) 242 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 243 | mockObj.getSomethingWithArgs.calledWith(6, anyNumber()).mockReturnValue(7) 244 | 245 | expect(mockObj.getSomethingWithArgs(2, 2)).toBe(4) 246 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 247 | expect(mockObj.getSomethingWithArgs(6, 2)).toBe(7) 248 | expect(mockObj.getSomethingWithArgs(7, 2)).toBe(undefined) 249 | }) 250 | 251 | test('supports overriding with same args', () => { 252 | const mockObj = mock() 253 | mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(4) 254 | mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(3) 255 | 256 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 257 | }) 258 | 259 | test('Support vitest matcher', () => { 260 | const mockObj = mock() 261 | mockObj.getSomethingWithArgs.calledWith(expect.anything(), expect.anything()).mockReturnValue(3) 262 | 263 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 264 | }) 265 | 266 | test('Suport mix Matchers with literals and with vitest matcher', () => { 267 | const mockObj = mock() 268 | mockObj.getSomethingWithMoreArgs.calledWith(anyNumber(), expect.anything(), 3).mockReturnValue(4) 269 | 270 | expect(mockObj.getSomethingWithMoreArgs(1, 2, 3)).toBe(4) 271 | expect(mockObj.getSomethingWithMoreArgs(1, 2, 4)).toBeUndefined() 272 | }) 273 | 274 | test('Can use calledWith with an other mock', () => { 275 | const mockObj = mock() 276 | const mockArg = mock() 277 | mockObj.getNumberWithMockArg.calledWith(mockArg).mockReturnValue(4) 278 | 279 | expect(mockObj.getNumberWithMockArg(mockArg)).toBe(4) 280 | }) 281 | }) 282 | 283 | describe('Matchers with toHaveBeenCalledWith', () => { 284 | test('matchers allow all args to be Matcher based', () => { 285 | const mockObj: MockInt = mock() 286 | mockObj.getSomethingWithArgs(2, 4) 287 | expect(mockObj.getSomethingWithArgs).toHaveBeenCalledWith(anyNumber(), anyNumber()) 288 | }) 289 | 290 | test('matchers allow for a mix of Matcher and literal', () => { 291 | const mockObj: MockInt = mock() 292 | mockObj.getSomethingWithArgs(2, 4) 293 | expect(mockObj.getSomethingWithArgs).toHaveBeenCalledWith(anyNumber(), 4) 294 | }) 295 | 296 | test('matchers allow for not.toHaveBeenCalledWith', () => { 297 | const mockObj: MockInt = mock() 298 | mockObj.getSomethingWithArgs(2, 4) 299 | expect(mockObj.getSomethingWithArgs).not.toHaveBeenCalledWith(anyNumber(), 5) 300 | }) 301 | }) 302 | 303 | describe('Deep mock support for class variables which are functions but also have nested properties and functions', () => { 304 | test('can deep mock members', () => { 305 | const mockObj = mockDeep({ funcPropSupport: true }) 306 | const input = new Test1(1) 307 | mockObj.funcValueProp.nonDeepProp.calledWith(input).mockReturnValue(4) 308 | 309 | expect(mockObj.funcValueProp.nonDeepProp(input)).toBe(4) 310 | }) 311 | 312 | test('three or more level deep mock', () => { 313 | const mockObj = mockDeep({ funcPropSupport: true }) 314 | mockObj.funcValueProp.deepProp.deeperProp.getNumber.calledWith(1).mockReturnValue(4) 315 | 316 | expect(mockObj.funcValueProp.deepProp.deeperProp.getNumber(1)).toBe(4) 317 | }) 318 | 319 | test('maintains API for deep mocks', () => { 320 | const mockObj = mockDeep({ funcPropSupport: true }) 321 | mockObj.funcValueProp.deepProp.getNumber(100) 322 | 323 | expect(mockObj.funcValueProp.deepProp.getNumber.mock.calls[0][0]).toBe(100) 324 | }) 325 | 326 | test('deep expectation work as expected', () => { 327 | const mockObj = mockDeep() 328 | mockObj.funcValueProp.deepProp.getNumber(2) 329 | 330 | expect(mockObj.funcValueProp.deepProp.getNumber).toHaveBeenCalledTimes(1) 331 | }) 332 | 333 | test('can mock base function which have properties', () => { 334 | const mockObj = mockDeep() 335 | mockObj.funcValueProp.calledWith(1).mockReturnValue(2) 336 | 337 | expect(mockObj.funcValueProp(1)).toBe(2) 338 | }) 339 | 340 | test('base function expectation work as expected', () => { 341 | const mockObj = mockDeep() 342 | mockObj.funcValueProp(1) 343 | 344 | expect(mockObj.funcValueProp).toHaveBeenCalledTimes(1) 345 | }) 346 | }) 347 | 348 | describe('Deep mock support', () => { 349 | test('can deep mock members', () => { 350 | const mockObj = mockDeep() 351 | mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4) 352 | expect(mockObj.deepProp.getNumber(1)).toBe(4) 353 | }) 354 | 355 | test('three level deep mock', () => { 356 | const mockObj = mockDeep() 357 | mockObj.deepProp.deeperProp.getNumber.calledWith(1).mockReturnValue(4) 358 | expect(mockObj.deepProp.deeperProp.getNumber(1)).toBe(4) 359 | }) 360 | 361 | test('maintains API for deep mocks', () => { 362 | const mockObj = mockDeep() 363 | mockObj.deepProp.getNumber(100) 364 | 365 | expect(mockObj.deepProp.getNumber.mock.calls[0][0]).toBe(100) 366 | }) 367 | 368 | test('non deep expectation work as expected', () => { 369 | const mockObj = mockDeep() 370 | new Test1(1).ofAnother(mockObj) 371 | expect(mockObj.getNumber).toHaveBeenCalledTimes(1) 372 | }) 373 | 374 | test('deep expectation work as expected', () => { 375 | const mockObj = mockDeep() 376 | mockObj.deepProp.getNumber(2) 377 | expect(mockObj.deepProp.getNumber).toHaveBeenCalledTimes(1) 378 | }) 379 | 380 | test('fallback mock implementation can be overridden', () => { 381 | const mockObj = mockDeep({ 382 | fallbackMockImplementation: () => { 383 | throw new Error('not mocked') 384 | }, 385 | }) 386 | mockObj.deepProp.getAnotherString.calledWith('foo') // no mock implementation 387 | expect(() => mockObj.getNumber()).toThrowError('not mocked') 388 | expect(() => mockObj.deepProp.getAnotherString('foo')).toThrowError('not mocked') 389 | }) 390 | 391 | test('fallback mock implementation can be overridden while also providing a mock implementation', () => { 392 | const mockObj = mockDeep( 393 | { 394 | fallbackMockImplementation: () => { 395 | throw new Error('not mocked') 396 | }, 397 | }, 398 | { 399 | getNumber: () => { 400 | return 150 401 | }, 402 | }, 403 | ) 404 | 405 | mockObj.deepProp.getAnotherString.calledWith('?').mockReturnValue('mocked') 406 | expect(mockObj.getNumber()).toBe(150) 407 | expect(mockObj.deepProp.getAnotherString('?')).toBe('mocked') 408 | expect(() => mockObj.deepProp.getNumber(1)).toThrowError('not mocked') 409 | expect(() => mockObj.deepProp.getAnotherString('!')).toThrowError('not mocked') 410 | }) 411 | }) 412 | 413 | describe('mock implementation support', () => { 414 | test('can provide mock implementation for props', () => { 415 | const mockObj = mock({ 416 | id: 61, 417 | }) 418 | expect(mockObj.id).toBe(61) 419 | }) 420 | 421 | test('can provide mock implementation for functions', () => { 422 | const mockObj = mock({ 423 | getNumber: () => { 424 | return 150 425 | }, 426 | }) 427 | expect(mockObj.getNumber()).toBe(150) 428 | }) 429 | 430 | test('Partially mocked implementations can have non-mocked function expectations', () => { 431 | const mockObj = mock({ 432 | getNumber: () => { 433 | return 150 434 | }, 435 | }) 436 | 437 | mockObj.getSomethingWithArgs.calledWith(1, 2).mockReturnValue(3) 438 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 439 | }) 440 | 441 | test('can provide deep mock implementations', () => { 442 | const mockObj = mockDeep({ 443 | deepProp: { 444 | getNumber: (_num: number) => { 445 | return 76 446 | }, 447 | }, 448 | }) 449 | expect(mockObj.deepProp.getNumber(123)).toBe(76) 450 | }) 451 | 452 | test('Partially mocked implementations of deep mocks can have non-mocked function expectations', () => { 453 | const mockObj = mockDeep({ 454 | deepProp: { 455 | getNumber: (_num: number) => { 456 | return 76 457 | }, 458 | }, 459 | }) 460 | 461 | mockObj.deepProp.getAnotherString.calledWith('abc').mockReturnValue('this string') 462 | expect(mockObj.deepProp.getAnotherString('abc')).toBe('this string') 463 | }) 464 | }) 465 | 466 | describe('Promise', () => { 467 | test('Can return as Promise.resolve', async () => { 468 | const mockObj = mock() 469 | mockObj.id = 17 470 | const promiseMockObj = Promise.resolve(mockObj) 471 | await expect(promiseMockObj).resolves.toBeDefined() 472 | await expect(promiseMockObj).resolves.toMatchObject({ id: 17 }) 473 | }) 474 | 475 | test('Can return as Promise.reject', async () => { 476 | const mockError = mock() 477 | mockError.message = '17' 478 | const promiseMockObj = Promise.reject(mockError) 479 | try { 480 | await promiseMockObj 481 | throw new Error('Promise must be rejected') 482 | } catch (e) { 483 | expect(e).toBeDefined() 484 | expect(e).toBe(mockError) 485 | expect(e).toHaveProperty('message', '17') 486 | } 487 | await expect(promiseMockObj).rejects.toBeDefined() 488 | await expect(promiseMockObj).rejects.toBe(mockError) 489 | await expect(promiseMockObj).rejects.toHaveProperty('message', '17') 490 | }) 491 | 492 | test('Can mock a then function', async () => { 493 | const mockPromiseObj = Promise.resolve(42) 494 | const mockObj = mock() 495 | mockObj.id = 17 496 | // @ts-expect-error as then is not defined on the MockInt type 497 | mockObj.then = mockPromiseObj.then.bind(mockPromiseObj) 498 | const promiseMockObj = Promise.resolve(mockObj) 499 | await promiseMockObj 500 | await expect(promiseMockObj).resolves.toBeDefined() 501 | await expect(promiseMockObj).resolves.toEqual(42) 502 | }) 503 | }) 504 | 505 | describe('clearing / resetting', () => { 506 | test('mockReset supports vi.fn()', () => { 507 | const fn = vi.fn().mockImplementation(() => true) 508 | expect(fn()).toBe(true) 509 | mockReset(fn) 510 | expect(fn()).toBe(undefined) 511 | }) 512 | 513 | test('mockClear supports vi.fn()', () => { 514 | const fn = vi.fn().mockImplementation(() => true) 515 | fn() 516 | expect(fn.mock.calls.length).toBe(1) 517 | mockClear(fn) 518 | expect(fn.mock.calls.length).toBe(0) 519 | }) 520 | 521 | test('mockReset object', () => { 522 | const mockObj = mock() 523 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 524 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 525 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 526 | mockReset(mockObj) 527 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(undefined) 528 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 529 | const x = mockObj.getSomethingWithArgs(1, 2) 530 | expect(x).toBe(3) 531 | }) 532 | 533 | test('mockClear object', () => { 534 | const mockObj = mock() 535 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 536 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 537 | expect(mockObj.getSomethingWithArgs.mock.calls.length).toBe(1) 538 | mockClear(mockObj) 539 | expect(mockObj.getSomethingWithArgs.mock.calls.length).toBe(0) 540 | // Does not clear mock implementations of calledWith 541 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 542 | }) 543 | 544 | test('mockReset deep', () => { 545 | const mockObj = mockDeep() 546 | mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4) 547 | expect(mockObj.deepProp.getNumber(1)).toBe(4) 548 | mockReset(mockObj) 549 | expect(mockObj.deepProp.getNumber(1)).toBe(undefined) 550 | }) 551 | 552 | test('mockClear deep', () => { 553 | const mockObj = mockDeep() 554 | mockObj.deepProp.getNumber.calledWith(1).mockReturnValue(4) 555 | expect(mockObj.deepProp.getNumber(1)).toBe(4) 556 | expect(mockObj.deepProp.getNumber.mock.calls.length).toBe(1) 557 | mockClear(mockObj) 558 | expect(mockObj.deepProp.getNumber.mock.calls.length).toBe(0) 559 | // Does not clear mock implementations of calledWith 560 | expect(mockObj.deepProp.getNumber(1)).toBe(4) 561 | }) 562 | 563 | test('mockReset ignores undefined properties', () => { 564 | const mockObj = mock() 565 | mockObj.someValue = undefined 566 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 567 | mockReset(mockObj) 568 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(undefined) 569 | }) 570 | 571 | test('mockReset ignores null properties', () => { 572 | const mockObj = mock() 573 | mockObj.someValue = null 574 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 575 | mockReset(mockObj) 576 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(undefined) 577 | }) 578 | 579 | test('mockClear ignores undefined properties', () => { 580 | const mockObj = mock() 581 | mockObj.someValue = undefined 582 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 583 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 584 | expect(mockObj.getSomethingWithArgs.mock.calls.length).toBe(1) 585 | mockClear(mockObj) 586 | expect(mockObj.getSomethingWithArgs.mock.calls.length).toBe(0) 587 | }) 588 | 589 | test('mockClear ignores null properties', () => { 590 | const mockObj = mock() 591 | mockObj.someValue = null 592 | mockObj.getSomethingWithArgs.calledWith(1, anyNumber()).mockReturnValue(3) 593 | expect(mockObj.getSomethingWithArgs(1, 2)).toBe(3) 594 | expect(mockObj.getSomethingWithArgs.mock.calls.length).toBe(1) 595 | mockClear(mockObj) 596 | expect(mockObj.getSomethingWithArgs.mock.calls.length).toBe(0) 597 | }) 598 | }) 599 | 600 | describe('function mock', () => { 601 | test('should mock function', async () => { 602 | type MyFn = (x: number, y: number) => Promise 603 | const mockFunc = mockFn() 604 | mockFunc.mockResolvedValue(`str`) 605 | const result: string = await mockFunc(1, 2) 606 | expect(result).toBe(`str`) 607 | }) 608 | test('should mock function and use calledWith', async () => { 609 | type MyFn = (x: number, y: number) => Promise 610 | const mockFunc = mockFn() 611 | mockFunc.calledWith(1, 2).mockResolvedValue(`str`) 612 | const result: string = await mockFunc(1, 2) 613 | expect(result).toBe(`str`) 614 | }) 615 | }) 616 | 617 | describe('ignoreProps', () => { 618 | test('can configure ignoreProps', async () => { 619 | VitestMockExtended.configure({ ignoreProps: ['ignoreMe'] }) 620 | const mockObj = mock<{ ignoreMe: string; dontIgnoreMe: string }>() 621 | expect(mockObj.ignoreMe).toBeUndefined() 622 | expect(mockObj.dontIgnoreMe).toBeDefined() 623 | }) 624 | }) 625 | 626 | describe('VitestMockExtended config', () => { 627 | test('can mock then', async () => { 628 | VitestMockExtended.configure({ ignoreProps: [] }) 629 | const mockObj = mock<{ then: () => void }>() 630 | mockObj.then() 631 | expect(mockObj.then).toHaveBeenCalled() 632 | }) 633 | 634 | test('can reset config', async () => { 635 | VitestMockExtended.configure({ ignoreProps: [] }) 636 | VitestMockExtended.resetConfig() 637 | const mockObj = mock<{ then: () => void }>() 638 | expect(mockObj.then).toBeUndefined() 639 | }) 640 | }) 641 | 642 | describe('mock Date', () => { 643 | test('should call built-in date functions', () => { 644 | type objWithDate = { date: Date } 645 | const unixTimestamp = Date.parse("15 Jan 2000 00:00:00 UTC") 646 | const mockObj = mock({ date: new Date(unixTimestamp) }) 647 | expect(mockObj.date.getFullYear()).toBe(2000) 648 | expect(mockObj.date.getMonth()).toBe(0) 649 | expect(mockObj.date.getDate()).toBe(15) 650 | }) 651 | }) 652 | 653 | describe('toJSON', () => { 654 | it('should properly stringify mock given option is set', () => { 655 | //given 656 | interface Test { 657 | test: string 658 | hello: number 659 | } 660 | const mocked = mock({ test: 'default' }, { useActualToJSON: true }) 661 | 662 | //when 663 | const stringified = JSON.stringify(mocked) 664 | 665 | //then 666 | expect(stringified).toStrictEqual('{"test":"default","_isMockObject":true}') 667 | }) 668 | 669 | it('should not stringify given option not set', () => { 670 | //given 671 | interface Test { 672 | test: string 673 | hello: number 674 | } 675 | const mocked = mock({ test: 'default' }, { useActualToJSON: false }) 676 | 677 | //when 678 | const stringified = JSON.stringify(mocked) 679 | 680 | //then 681 | expect(stringified).toBeUndefined() 682 | }) 683 | 684 | it('should stricktly equal after stringify', () => { 685 | //given 686 | interface Test { 687 | cookie: { 688 | domain: string 689 | } 690 | } 691 | const cookie = { domain: 'dummy' } 692 | const data = mock({ cookie }) 693 | 694 | //when 695 | JSON.stringify(data) 696 | 697 | //when 698 | expect({ cookie: { domain: 'dummy' } }).toStrictEqual({ cookie }) 699 | }) 700 | }) 701 | 702 | describe('mock type utils', () => { 703 | it('mocked should handle mock obj', () => { 704 | const mockObj = mock() 705 | const obj = mocked(mockObj) 706 | 707 | expect(obj.getNumber).toHaveBeenCalledTimes(0) 708 | }) 709 | 710 | it('mocked should handle mockDeep obj', () => { 711 | const mockObj = mockDeep({ funcPropSupport: true }) 712 | const input = new Test1(1) 713 | mockObj.funcValueProp.nonDeepProp.calledWith(input).mockReturnValue(4) 714 | const obj = mocked(mockObj, true) 715 | 716 | expect(obj.funcValueProp.nonDeepProp(input)).toBe(4) 717 | }) 718 | 719 | it('mockedFn should handle mockFn obj', async () => { 720 | type MyFn = (x: number, y: number) => Promise 721 | const mockFunc = mockFn() 722 | mockFunc.mockResolvedValue(`str`) 723 | 724 | const obj = mockedFn(mockFunc) 725 | const result: string = await obj(1, 2) 726 | expect(result).toBe(`str`) 727 | }) 728 | }) 729 | }) 730 | -------------------------------------------------------------------------------- /example/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@types/node': 12 | specifier: 24.10.1 13 | version: 24.10.1 14 | '@vitest/coverage-v8': 15 | specifier: 3.0.6 16 | version: 3.0.6(vitest@3.0.6(@types/node@24.10.1)) 17 | ts-node: 18 | specifier: 10.9.2 19 | version: 10.9.2(@types/node@24.10.1)(typescript@5.5.3) 20 | tsm: 21 | specifier: 2.3.0 22 | version: 2.3.0 23 | typescript: 24 | specifier: 5.5.3 25 | version: 5.5.3 26 | vitest: 27 | specifier: 3.0.6 28 | version: 3.0.6(@types/node@24.10.1) 29 | vitest-mock-extended: 30 | specifier: link:.. 31 | version: link:.. 32 | 33 | packages: 34 | 35 | '@ampproject/remapping@2.3.0': 36 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 37 | engines: {node: '>=6.0.0'} 38 | 39 | '@babel/helper-string-parser@7.25.9': 40 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 41 | engines: {node: '>=6.9.0'} 42 | 43 | '@babel/helper-validator-identifier@7.25.9': 44 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 45 | engines: {node: '>=6.9.0'} 46 | 47 | '@babel/parser@7.26.9': 48 | resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} 49 | engines: {node: '>=6.0.0'} 50 | hasBin: true 51 | 52 | '@babel/types@7.26.9': 53 | resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} 54 | engines: {node: '>=6.9.0'} 55 | 56 | '@bcoe/v8-coverage@1.0.2': 57 | resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} 58 | engines: {node: '>=18'} 59 | 60 | '@cspotcode/source-map-support@0.8.1': 61 | resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 62 | engines: {node: '>=12'} 63 | 64 | '@esbuild/aix-ppc64@0.21.5': 65 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 66 | engines: {node: '>=12'} 67 | cpu: [ppc64] 68 | os: [aix] 69 | 70 | '@esbuild/android-arm64@0.21.5': 71 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 72 | engines: {node: '>=12'} 73 | cpu: [arm64] 74 | os: [android] 75 | 76 | '@esbuild/android-arm@0.15.18': 77 | resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} 78 | engines: {node: '>=12'} 79 | cpu: [arm] 80 | os: [android] 81 | 82 | '@esbuild/android-arm@0.21.5': 83 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 84 | engines: {node: '>=12'} 85 | cpu: [arm] 86 | os: [android] 87 | 88 | '@esbuild/android-x64@0.21.5': 89 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 90 | engines: {node: '>=12'} 91 | cpu: [x64] 92 | os: [android] 93 | 94 | '@esbuild/darwin-arm64@0.21.5': 95 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 96 | engines: {node: '>=12'} 97 | cpu: [arm64] 98 | os: [darwin] 99 | 100 | '@esbuild/darwin-x64@0.21.5': 101 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 102 | engines: {node: '>=12'} 103 | cpu: [x64] 104 | os: [darwin] 105 | 106 | '@esbuild/freebsd-arm64@0.21.5': 107 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 108 | engines: {node: '>=12'} 109 | cpu: [arm64] 110 | os: [freebsd] 111 | 112 | '@esbuild/freebsd-x64@0.21.5': 113 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 114 | engines: {node: '>=12'} 115 | cpu: [x64] 116 | os: [freebsd] 117 | 118 | '@esbuild/linux-arm64@0.21.5': 119 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 120 | engines: {node: '>=12'} 121 | cpu: [arm64] 122 | os: [linux] 123 | 124 | '@esbuild/linux-arm@0.21.5': 125 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 126 | engines: {node: '>=12'} 127 | cpu: [arm] 128 | os: [linux] 129 | 130 | '@esbuild/linux-ia32@0.21.5': 131 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 132 | engines: {node: '>=12'} 133 | cpu: [ia32] 134 | os: [linux] 135 | 136 | '@esbuild/linux-loong64@0.15.18': 137 | resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} 138 | engines: {node: '>=12'} 139 | cpu: [loong64] 140 | os: [linux] 141 | 142 | '@esbuild/linux-loong64@0.21.5': 143 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 144 | engines: {node: '>=12'} 145 | cpu: [loong64] 146 | os: [linux] 147 | 148 | '@esbuild/linux-mips64el@0.21.5': 149 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 150 | engines: {node: '>=12'} 151 | cpu: [mips64el] 152 | os: [linux] 153 | 154 | '@esbuild/linux-ppc64@0.21.5': 155 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 156 | engines: {node: '>=12'} 157 | cpu: [ppc64] 158 | os: [linux] 159 | 160 | '@esbuild/linux-riscv64@0.21.5': 161 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 162 | engines: {node: '>=12'} 163 | cpu: [riscv64] 164 | os: [linux] 165 | 166 | '@esbuild/linux-s390x@0.21.5': 167 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 168 | engines: {node: '>=12'} 169 | cpu: [s390x] 170 | os: [linux] 171 | 172 | '@esbuild/linux-x64@0.21.5': 173 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 174 | engines: {node: '>=12'} 175 | cpu: [x64] 176 | os: [linux] 177 | 178 | '@esbuild/netbsd-x64@0.21.5': 179 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 180 | engines: {node: '>=12'} 181 | cpu: [x64] 182 | os: [netbsd] 183 | 184 | '@esbuild/openbsd-x64@0.21.5': 185 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 186 | engines: {node: '>=12'} 187 | cpu: [x64] 188 | os: [openbsd] 189 | 190 | '@esbuild/sunos-x64@0.21.5': 191 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 192 | engines: {node: '>=12'} 193 | cpu: [x64] 194 | os: [sunos] 195 | 196 | '@esbuild/win32-arm64@0.21.5': 197 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 198 | engines: {node: '>=12'} 199 | cpu: [arm64] 200 | os: [win32] 201 | 202 | '@esbuild/win32-ia32@0.21.5': 203 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 204 | engines: {node: '>=12'} 205 | cpu: [ia32] 206 | os: [win32] 207 | 208 | '@esbuild/win32-x64@0.21.5': 209 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 210 | engines: {node: '>=12'} 211 | cpu: [x64] 212 | os: [win32] 213 | 214 | '@isaacs/cliui@8.0.2': 215 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 216 | engines: {node: '>=12'} 217 | 218 | '@istanbuljs/schema@0.1.3': 219 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} 220 | engines: {node: '>=8'} 221 | 222 | '@jridgewell/gen-mapping@0.3.5': 223 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 224 | engines: {node: '>=6.0.0'} 225 | 226 | '@jridgewell/resolve-uri@3.1.2': 227 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 228 | engines: {node: '>=6.0.0'} 229 | 230 | '@jridgewell/set-array@1.2.1': 231 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 232 | engines: {node: '>=6.0.0'} 233 | 234 | '@jridgewell/sourcemap-codec@1.4.15': 235 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 236 | 237 | '@jridgewell/sourcemap-codec@1.5.0': 238 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 239 | 240 | '@jridgewell/trace-mapping@0.3.25': 241 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 242 | 243 | '@jridgewell/trace-mapping@0.3.9': 244 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 245 | 246 | '@pkgjs/parseargs@0.11.0': 247 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 248 | engines: {node: '>=14'} 249 | 250 | '@rollup/rollup-android-arm-eabi@4.24.0': 251 | resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} 252 | cpu: [arm] 253 | os: [android] 254 | 255 | '@rollup/rollup-android-arm64@4.24.0': 256 | resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} 257 | cpu: [arm64] 258 | os: [android] 259 | 260 | '@rollup/rollup-darwin-arm64@4.24.0': 261 | resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} 262 | cpu: [arm64] 263 | os: [darwin] 264 | 265 | '@rollup/rollup-darwin-x64@4.24.0': 266 | resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} 267 | cpu: [x64] 268 | os: [darwin] 269 | 270 | '@rollup/rollup-linux-arm-gnueabihf@4.24.0': 271 | resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} 272 | cpu: [arm] 273 | os: [linux] 274 | 275 | '@rollup/rollup-linux-arm-musleabihf@4.24.0': 276 | resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} 277 | cpu: [arm] 278 | os: [linux] 279 | 280 | '@rollup/rollup-linux-arm64-gnu@4.24.0': 281 | resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} 282 | cpu: [arm64] 283 | os: [linux] 284 | 285 | '@rollup/rollup-linux-arm64-musl@4.24.0': 286 | resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} 287 | cpu: [arm64] 288 | os: [linux] 289 | 290 | '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': 291 | resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} 292 | cpu: [ppc64] 293 | os: [linux] 294 | 295 | '@rollup/rollup-linux-riscv64-gnu@4.24.0': 296 | resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} 297 | cpu: [riscv64] 298 | os: [linux] 299 | 300 | '@rollup/rollup-linux-s390x-gnu@4.24.0': 301 | resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} 302 | cpu: [s390x] 303 | os: [linux] 304 | 305 | '@rollup/rollup-linux-x64-gnu@4.24.0': 306 | resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} 307 | cpu: [x64] 308 | os: [linux] 309 | 310 | '@rollup/rollup-linux-x64-musl@4.24.0': 311 | resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} 312 | cpu: [x64] 313 | os: [linux] 314 | 315 | '@rollup/rollup-win32-arm64-msvc@4.24.0': 316 | resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} 317 | cpu: [arm64] 318 | os: [win32] 319 | 320 | '@rollup/rollup-win32-ia32-msvc@4.24.0': 321 | resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} 322 | cpu: [ia32] 323 | os: [win32] 324 | 325 | '@rollup/rollup-win32-x64-msvc@4.24.0': 326 | resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} 327 | cpu: [x64] 328 | os: [win32] 329 | 330 | '@tsconfig/node10@1.0.11': 331 | resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} 332 | 333 | '@tsconfig/node12@1.0.11': 334 | resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} 335 | 336 | '@tsconfig/node14@1.0.3': 337 | resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} 338 | 339 | '@tsconfig/node16@1.0.4': 340 | resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} 341 | 342 | '@types/estree@1.0.6': 343 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 344 | 345 | '@types/node@24.10.1': 346 | resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} 347 | 348 | '@vitest/coverage-v8@3.0.6': 349 | resolution: {integrity: sha512-JRTlR8Bw+4BcmVTICa7tJsxqphAktakiLsAmibVLAWbu1lauFddY/tXeM6sAyl1cgkPuXtpnUgaCPhTdz1Qapg==} 350 | peerDependencies: 351 | '@vitest/browser': 3.0.6 352 | vitest: 3.0.6 353 | peerDependenciesMeta: 354 | '@vitest/browser': 355 | optional: true 356 | 357 | '@vitest/expect@3.0.6': 358 | resolution: {integrity: sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==} 359 | 360 | '@vitest/mocker@3.0.6': 361 | resolution: {integrity: sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==} 362 | peerDependencies: 363 | msw: ^2.4.9 364 | vite: ^5.0.0 || ^6.0.0 365 | peerDependenciesMeta: 366 | msw: 367 | optional: true 368 | vite: 369 | optional: true 370 | 371 | '@vitest/pretty-format@3.0.6': 372 | resolution: {integrity: sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==} 373 | 374 | '@vitest/runner@3.0.6': 375 | resolution: {integrity: sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==} 376 | 377 | '@vitest/snapshot@3.0.6': 378 | resolution: {integrity: sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==} 379 | 380 | '@vitest/spy@3.0.6': 381 | resolution: {integrity: sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==} 382 | 383 | '@vitest/utils@3.0.6': 384 | resolution: {integrity: sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==} 385 | 386 | acorn-walk@8.3.2: 387 | resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} 388 | engines: {node: '>=0.4.0'} 389 | 390 | acorn@8.11.3: 391 | resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} 392 | engines: {node: '>=0.4.0'} 393 | hasBin: true 394 | 395 | ansi-regex@5.0.1: 396 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 397 | engines: {node: '>=8'} 398 | 399 | ansi-regex@6.0.1: 400 | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} 401 | engines: {node: '>=12'} 402 | 403 | ansi-styles@4.3.0: 404 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 405 | engines: {node: '>=8'} 406 | 407 | ansi-styles@6.2.1: 408 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 409 | engines: {node: '>=12'} 410 | 411 | arg@4.1.3: 412 | resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} 413 | 414 | assertion-error@2.0.1: 415 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 416 | engines: {node: '>=12'} 417 | 418 | balanced-match@1.0.2: 419 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 420 | 421 | brace-expansion@2.0.1: 422 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 423 | 424 | cac@6.7.14: 425 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 426 | engines: {node: '>=8'} 427 | 428 | chai@5.2.0: 429 | resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} 430 | engines: {node: '>=12'} 431 | 432 | check-error@2.1.1: 433 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 434 | engines: {node: '>= 16'} 435 | 436 | color-convert@2.0.1: 437 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 438 | engines: {node: '>=7.0.0'} 439 | 440 | color-name@1.1.4: 441 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 442 | 443 | create-require@1.1.1: 444 | resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} 445 | 446 | cross-spawn@7.0.5: 447 | resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} 448 | engines: {node: '>= 8'} 449 | 450 | debug@4.4.0: 451 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 452 | engines: {node: '>=6.0'} 453 | peerDependencies: 454 | supports-color: '*' 455 | peerDependenciesMeta: 456 | supports-color: 457 | optional: true 458 | 459 | deep-eql@5.0.2: 460 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 461 | engines: {node: '>=6'} 462 | 463 | diff@4.0.2: 464 | resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} 465 | engines: {node: '>=0.3.1'} 466 | 467 | eastasianwidth@0.2.0: 468 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 469 | 470 | emoji-regex@8.0.0: 471 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 472 | 473 | emoji-regex@9.2.2: 474 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 475 | 476 | es-module-lexer@1.6.0: 477 | resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} 478 | 479 | esbuild-android-64@0.15.18: 480 | resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==} 481 | engines: {node: '>=12'} 482 | cpu: [x64] 483 | os: [android] 484 | 485 | esbuild-android-arm64@0.15.18: 486 | resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==} 487 | engines: {node: '>=12'} 488 | cpu: [arm64] 489 | os: [android] 490 | 491 | esbuild-darwin-64@0.15.18: 492 | resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==} 493 | engines: {node: '>=12'} 494 | cpu: [x64] 495 | os: [darwin] 496 | 497 | esbuild-darwin-arm64@0.15.18: 498 | resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==} 499 | engines: {node: '>=12'} 500 | cpu: [arm64] 501 | os: [darwin] 502 | 503 | esbuild-freebsd-64@0.15.18: 504 | resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==} 505 | engines: {node: '>=12'} 506 | cpu: [x64] 507 | os: [freebsd] 508 | 509 | esbuild-freebsd-arm64@0.15.18: 510 | resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==} 511 | engines: {node: '>=12'} 512 | cpu: [arm64] 513 | os: [freebsd] 514 | 515 | esbuild-linux-32@0.15.18: 516 | resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==} 517 | engines: {node: '>=12'} 518 | cpu: [ia32] 519 | os: [linux] 520 | 521 | esbuild-linux-64@0.15.18: 522 | resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==} 523 | engines: {node: '>=12'} 524 | cpu: [x64] 525 | os: [linux] 526 | 527 | esbuild-linux-arm64@0.15.18: 528 | resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==} 529 | engines: {node: '>=12'} 530 | cpu: [arm64] 531 | os: [linux] 532 | 533 | esbuild-linux-arm@0.15.18: 534 | resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==} 535 | engines: {node: '>=12'} 536 | cpu: [arm] 537 | os: [linux] 538 | 539 | esbuild-linux-mips64le@0.15.18: 540 | resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==} 541 | engines: {node: '>=12'} 542 | cpu: [mips64el] 543 | os: [linux] 544 | 545 | esbuild-linux-ppc64le@0.15.18: 546 | resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==} 547 | engines: {node: '>=12'} 548 | cpu: [ppc64] 549 | os: [linux] 550 | 551 | esbuild-linux-riscv64@0.15.18: 552 | resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==} 553 | engines: {node: '>=12'} 554 | cpu: [riscv64] 555 | os: [linux] 556 | 557 | esbuild-linux-s390x@0.15.18: 558 | resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==} 559 | engines: {node: '>=12'} 560 | cpu: [s390x] 561 | os: [linux] 562 | 563 | esbuild-netbsd-64@0.15.18: 564 | resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==} 565 | engines: {node: '>=12'} 566 | cpu: [x64] 567 | os: [netbsd] 568 | 569 | esbuild-openbsd-64@0.15.18: 570 | resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==} 571 | engines: {node: '>=12'} 572 | cpu: [x64] 573 | os: [openbsd] 574 | 575 | esbuild-sunos-64@0.15.18: 576 | resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} 577 | engines: {node: '>=12'} 578 | cpu: [x64] 579 | os: [sunos] 580 | 581 | esbuild-windows-32@0.15.18: 582 | resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==} 583 | engines: {node: '>=12'} 584 | cpu: [ia32] 585 | os: [win32] 586 | 587 | esbuild-windows-64@0.15.18: 588 | resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==} 589 | engines: {node: '>=12'} 590 | cpu: [x64] 591 | os: [win32] 592 | 593 | esbuild-windows-arm64@0.15.18: 594 | resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==} 595 | engines: {node: '>=12'} 596 | cpu: [arm64] 597 | os: [win32] 598 | 599 | esbuild@0.15.18: 600 | resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==} 601 | engines: {node: '>=12'} 602 | hasBin: true 603 | 604 | esbuild@0.21.5: 605 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 606 | engines: {node: '>=12'} 607 | hasBin: true 608 | 609 | estree-walker@3.0.3: 610 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 611 | 612 | expect-type@1.1.0: 613 | resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} 614 | engines: {node: '>=12.0.0'} 615 | 616 | foreground-child@3.2.1: 617 | resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} 618 | engines: {node: '>=14'} 619 | 620 | fsevents@2.3.3: 621 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 622 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 623 | os: [darwin] 624 | 625 | get-func-name@2.0.2: 626 | resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} 627 | 628 | glob@10.4.5: 629 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 630 | hasBin: true 631 | 632 | has-flag@4.0.0: 633 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 634 | engines: {node: '>=8'} 635 | 636 | html-escaper@2.0.2: 637 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 638 | 639 | is-fullwidth-code-point@3.0.0: 640 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 641 | engines: {node: '>=8'} 642 | 643 | isexe@2.0.0: 644 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 645 | 646 | istanbul-lib-coverage@3.2.2: 647 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} 648 | engines: {node: '>=8'} 649 | 650 | istanbul-lib-report@3.0.1: 651 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} 652 | engines: {node: '>=10'} 653 | 654 | istanbul-lib-source-maps@5.0.6: 655 | resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} 656 | engines: {node: '>=10'} 657 | 658 | istanbul-reports@3.1.7: 659 | resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} 660 | engines: {node: '>=8'} 661 | 662 | jackspeak@3.4.3: 663 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 664 | 665 | loupe@3.1.1: 666 | resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==} 667 | 668 | loupe@3.1.3: 669 | resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} 670 | 671 | lru-cache@10.4.3: 672 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 673 | 674 | lru-cache@6.0.0: 675 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 676 | engines: {node: '>=10'} 677 | 678 | magic-string@0.30.17: 679 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 680 | 681 | magicast@0.3.5: 682 | resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} 683 | 684 | make-dir@4.0.0: 685 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} 686 | engines: {node: '>=10'} 687 | 688 | make-error@1.3.6: 689 | resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 690 | 691 | minimatch@9.0.5: 692 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 693 | engines: {node: '>=16 || 14 >=14.17'} 694 | 695 | minipass@7.1.2: 696 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 697 | engines: {node: '>=16 || 14 >=14.17'} 698 | 699 | ms@2.1.3: 700 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 701 | 702 | nanoid@3.3.8: 703 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 704 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 705 | hasBin: true 706 | 707 | package-json-from-dist@1.0.0: 708 | resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} 709 | 710 | path-key@3.1.1: 711 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 712 | engines: {node: '>=8'} 713 | 714 | path-scurry@1.11.1: 715 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 716 | engines: {node: '>=16 || 14 >=14.18'} 717 | 718 | pathe@2.0.3: 719 | resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 720 | 721 | pathval@2.0.0: 722 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} 723 | engines: {node: '>= 14.16'} 724 | 725 | picocolors@1.1.0: 726 | resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} 727 | 728 | postcss@8.4.47: 729 | resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} 730 | engines: {node: ^10 || ^12 || >=14} 731 | 732 | rollup@4.24.0: 733 | resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} 734 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 735 | hasBin: true 736 | 737 | semver@7.6.0: 738 | resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} 739 | engines: {node: '>=10'} 740 | hasBin: true 741 | 742 | shebang-command@2.0.0: 743 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 744 | engines: {node: '>=8'} 745 | 746 | shebang-regex@3.0.0: 747 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 748 | engines: {node: '>=8'} 749 | 750 | siginfo@2.0.0: 751 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 752 | 753 | signal-exit@4.1.0: 754 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 755 | engines: {node: '>=14'} 756 | 757 | source-map-js@1.2.1: 758 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 759 | engines: {node: '>=0.10.0'} 760 | 761 | stackback@0.0.2: 762 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 763 | 764 | std-env@3.8.0: 765 | resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} 766 | 767 | string-width@4.2.3: 768 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 769 | engines: {node: '>=8'} 770 | 771 | string-width@5.1.2: 772 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 773 | engines: {node: '>=12'} 774 | 775 | strip-ansi@6.0.1: 776 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 777 | engines: {node: '>=8'} 778 | 779 | strip-ansi@7.1.0: 780 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 781 | engines: {node: '>=12'} 782 | 783 | supports-color@7.2.0: 784 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 785 | engines: {node: '>=8'} 786 | 787 | test-exclude@7.0.1: 788 | resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} 789 | engines: {node: '>=18'} 790 | 791 | tinybench@2.9.0: 792 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 793 | 794 | tinyexec@0.3.2: 795 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 796 | 797 | tinypool@1.0.2: 798 | resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} 799 | engines: {node: ^18.0.0 || >=20.0.0} 800 | 801 | tinyrainbow@2.0.0: 802 | resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} 803 | engines: {node: '>=14.0.0'} 804 | 805 | tinyspy@3.0.2: 806 | resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} 807 | engines: {node: '>=14.0.0'} 808 | 809 | ts-node@10.9.2: 810 | resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} 811 | hasBin: true 812 | peerDependencies: 813 | '@swc/core': '>=1.2.50' 814 | '@swc/wasm': '>=1.2.50' 815 | '@types/node': '*' 816 | typescript: '>=2.7' 817 | peerDependenciesMeta: 818 | '@swc/core': 819 | optional: true 820 | '@swc/wasm': 821 | optional: true 822 | 823 | tsm@2.3.0: 824 | resolution: {integrity: sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==} 825 | engines: {node: '>=12'} 826 | hasBin: true 827 | 828 | typescript@5.5.3: 829 | resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} 830 | engines: {node: '>=14.17'} 831 | hasBin: true 832 | 833 | undici-types@7.16.0: 834 | resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 835 | 836 | v8-compile-cache-lib@3.0.1: 837 | resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} 838 | 839 | vite-node@3.0.6: 840 | resolution: {integrity: sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==} 841 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 842 | hasBin: true 843 | 844 | vite@5.4.8: 845 | resolution: {integrity: sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==} 846 | engines: {node: ^18.0.0 || >=20.0.0} 847 | hasBin: true 848 | peerDependencies: 849 | '@types/node': ^18.0.0 || >=20.0.0 850 | less: '*' 851 | lightningcss: ^1.21.0 852 | sass: '*' 853 | sass-embedded: '*' 854 | stylus: '*' 855 | sugarss: '*' 856 | terser: ^5.4.0 857 | peerDependenciesMeta: 858 | '@types/node': 859 | optional: true 860 | less: 861 | optional: true 862 | lightningcss: 863 | optional: true 864 | sass: 865 | optional: true 866 | sass-embedded: 867 | optional: true 868 | stylus: 869 | optional: true 870 | sugarss: 871 | optional: true 872 | terser: 873 | optional: true 874 | 875 | vitest@3.0.6: 876 | resolution: {integrity: sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==} 877 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 878 | hasBin: true 879 | peerDependencies: 880 | '@edge-runtime/vm': '*' 881 | '@types/debug': ^4.1.12 882 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 883 | '@vitest/browser': 3.0.6 884 | '@vitest/ui': 3.0.6 885 | happy-dom: '*' 886 | jsdom: '*' 887 | peerDependenciesMeta: 888 | '@edge-runtime/vm': 889 | optional: true 890 | '@types/debug': 891 | optional: true 892 | '@types/node': 893 | optional: true 894 | '@vitest/browser': 895 | optional: true 896 | '@vitest/ui': 897 | optional: true 898 | happy-dom: 899 | optional: true 900 | jsdom: 901 | optional: true 902 | 903 | which@2.0.2: 904 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 905 | engines: {node: '>= 8'} 906 | hasBin: true 907 | 908 | why-is-node-running@2.3.0: 909 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 910 | engines: {node: '>=8'} 911 | hasBin: true 912 | 913 | wrap-ansi@7.0.0: 914 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 915 | engines: {node: '>=10'} 916 | 917 | wrap-ansi@8.1.0: 918 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 919 | engines: {node: '>=12'} 920 | 921 | yallist@4.0.0: 922 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 923 | 924 | yn@3.1.1: 925 | resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} 926 | engines: {node: '>=6'} 927 | 928 | snapshots: 929 | 930 | '@ampproject/remapping@2.3.0': 931 | dependencies: 932 | '@jridgewell/gen-mapping': 0.3.5 933 | '@jridgewell/trace-mapping': 0.3.25 934 | 935 | '@babel/helper-string-parser@7.25.9': {} 936 | 937 | '@babel/helper-validator-identifier@7.25.9': {} 938 | 939 | '@babel/parser@7.26.9': 940 | dependencies: 941 | '@babel/types': 7.26.9 942 | 943 | '@babel/types@7.26.9': 944 | dependencies: 945 | '@babel/helper-string-parser': 7.25.9 946 | '@babel/helper-validator-identifier': 7.25.9 947 | 948 | '@bcoe/v8-coverage@1.0.2': {} 949 | 950 | '@cspotcode/source-map-support@0.8.1': 951 | dependencies: 952 | '@jridgewell/trace-mapping': 0.3.9 953 | 954 | '@esbuild/aix-ppc64@0.21.5': 955 | optional: true 956 | 957 | '@esbuild/android-arm64@0.21.5': 958 | optional: true 959 | 960 | '@esbuild/android-arm@0.15.18': 961 | optional: true 962 | 963 | '@esbuild/android-arm@0.21.5': 964 | optional: true 965 | 966 | '@esbuild/android-x64@0.21.5': 967 | optional: true 968 | 969 | '@esbuild/darwin-arm64@0.21.5': 970 | optional: true 971 | 972 | '@esbuild/darwin-x64@0.21.5': 973 | optional: true 974 | 975 | '@esbuild/freebsd-arm64@0.21.5': 976 | optional: true 977 | 978 | '@esbuild/freebsd-x64@0.21.5': 979 | optional: true 980 | 981 | '@esbuild/linux-arm64@0.21.5': 982 | optional: true 983 | 984 | '@esbuild/linux-arm@0.21.5': 985 | optional: true 986 | 987 | '@esbuild/linux-ia32@0.21.5': 988 | optional: true 989 | 990 | '@esbuild/linux-loong64@0.15.18': 991 | optional: true 992 | 993 | '@esbuild/linux-loong64@0.21.5': 994 | optional: true 995 | 996 | '@esbuild/linux-mips64el@0.21.5': 997 | optional: true 998 | 999 | '@esbuild/linux-ppc64@0.21.5': 1000 | optional: true 1001 | 1002 | '@esbuild/linux-riscv64@0.21.5': 1003 | optional: true 1004 | 1005 | '@esbuild/linux-s390x@0.21.5': 1006 | optional: true 1007 | 1008 | '@esbuild/linux-x64@0.21.5': 1009 | optional: true 1010 | 1011 | '@esbuild/netbsd-x64@0.21.5': 1012 | optional: true 1013 | 1014 | '@esbuild/openbsd-x64@0.21.5': 1015 | optional: true 1016 | 1017 | '@esbuild/sunos-x64@0.21.5': 1018 | optional: true 1019 | 1020 | '@esbuild/win32-arm64@0.21.5': 1021 | optional: true 1022 | 1023 | '@esbuild/win32-ia32@0.21.5': 1024 | optional: true 1025 | 1026 | '@esbuild/win32-x64@0.21.5': 1027 | optional: true 1028 | 1029 | '@isaacs/cliui@8.0.2': 1030 | dependencies: 1031 | string-width: 5.1.2 1032 | string-width-cjs: string-width@4.2.3 1033 | strip-ansi: 7.1.0 1034 | strip-ansi-cjs: strip-ansi@6.0.1 1035 | wrap-ansi: 8.1.0 1036 | wrap-ansi-cjs: wrap-ansi@7.0.0 1037 | 1038 | '@istanbuljs/schema@0.1.3': {} 1039 | 1040 | '@jridgewell/gen-mapping@0.3.5': 1041 | dependencies: 1042 | '@jridgewell/set-array': 1.2.1 1043 | '@jridgewell/sourcemap-codec': 1.4.15 1044 | '@jridgewell/trace-mapping': 0.3.25 1045 | 1046 | '@jridgewell/resolve-uri@3.1.2': {} 1047 | 1048 | '@jridgewell/set-array@1.2.1': {} 1049 | 1050 | '@jridgewell/sourcemap-codec@1.4.15': {} 1051 | 1052 | '@jridgewell/sourcemap-codec@1.5.0': {} 1053 | 1054 | '@jridgewell/trace-mapping@0.3.25': 1055 | dependencies: 1056 | '@jridgewell/resolve-uri': 3.1.2 1057 | '@jridgewell/sourcemap-codec': 1.4.15 1058 | 1059 | '@jridgewell/trace-mapping@0.3.9': 1060 | dependencies: 1061 | '@jridgewell/resolve-uri': 3.1.2 1062 | '@jridgewell/sourcemap-codec': 1.4.15 1063 | 1064 | '@pkgjs/parseargs@0.11.0': 1065 | optional: true 1066 | 1067 | '@rollup/rollup-android-arm-eabi@4.24.0': 1068 | optional: true 1069 | 1070 | '@rollup/rollup-android-arm64@4.24.0': 1071 | optional: true 1072 | 1073 | '@rollup/rollup-darwin-arm64@4.24.0': 1074 | optional: true 1075 | 1076 | '@rollup/rollup-darwin-x64@4.24.0': 1077 | optional: true 1078 | 1079 | '@rollup/rollup-linux-arm-gnueabihf@4.24.0': 1080 | optional: true 1081 | 1082 | '@rollup/rollup-linux-arm-musleabihf@4.24.0': 1083 | optional: true 1084 | 1085 | '@rollup/rollup-linux-arm64-gnu@4.24.0': 1086 | optional: true 1087 | 1088 | '@rollup/rollup-linux-arm64-musl@4.24.0': 1089 | optional: true 1090 | 1091 | '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': 1092 | optional: true 1093 | 1094 | '@rollup/rollup-linux-riscv64-gnu@4.24.0': 1095 | optional: true 1096 | 1097 | '@rollup/rollup-linux-s390x-gnu@4.24.0': 1098 | optional: true 1099 | 1100 | '@rollup/rollup-linux-x64-gnu@4.24.0': 1101 | optional: true 1102 | 1103 | '@rollup/rollup-linux-x64-musl@4.24.0': 1104 | optional: true 1105 | 1106 | '@rollup/rollup-win32-arm64-msvc@4.24.0': 1107 | optional: true 1108 | 1109 | '@rollup/rollup-win32-ia32-msvc@4.24.0': 1110 | optional: true 1111 | 1112 | '@rollup/rollup-win32-x64-msvc@4.24.0': 1113 | optional: true 1114 | 1115 | '@tsconfig/node10@1.0.11': {} 1116 | 1117 | '@tsconfig/node12@1.0.11': {} 1118 | 1119 | '@tsconfig/node14@1.0.3': {} 1120 | 1121 | '@tsconfig/node16@1.0.4': {} 1122 | 1123 | '@types/estree@1.0.6': {} 1124 | 1125 | '@types/node@24.10.1': 1126 | dependencies: 1127 | undici-types: 7.16.0 1128 | 1129 | '@vitest/coverage-v8@3.0.6(vitest@3.0.6(@types/node@24.10.1))': 1130 | dependencies: 1131 | '@ampproject/remapping': 2.3.0 1132 | '@bcoe/v8-coverage': 1.0.2 1133 | debug: 4.4.0 1134 | istanbul-lib-coverage: 3.2.2 1135 | istanbul-lib-report: 3.0.1 1136 | istanbul-lib-source-maps: 5.0.6 1137 | istanbul-reports: 3.1.7 1138 | magic-string: 0.30.17 1139 | magicast: 0.3.5 1140 | std-env: 3.8.0 1141 | test-exclude: 7.0.1 1142 | tinyrainbow: 2.0.0 1143 | vitest: 3.0.6(@types/node@24.10.1) 1144 | transitivePeerDependencies: 1145 | - supports-color 1146 | 1147 | '@vitest/expect@3.0.6': 1148 | dependencies: 1149 | '@vitest/spy': 3.0.6 1150 | '@vitest/utils': 3.0.6 1151 | chai: 5.2.0 1152 | tinyrainbow: 2.0.0 1153 | 1154 | '@vitest/mocker@3.0.6(vite@5.4.8(@types/node@24.10.1))': 1155 | dependencies: 1156 | '@vitest/spy': 3.0.6 1157 | estree-walker: 3.0.3 1158 | magic-string: 0.30.17 1159 | optionalDependencies: 1160 | vite: 5.4.8(@types/node@24.10.1) 1161 | 1162 | '@vitest/pretty-format@3.0.6': 1163 | dependencies: 1164 | tinyrainbow: 2.0.0 1165 | 1166 | '@vitest/runner@3.0.6': 1167 | dependencies: 1168 | '@vitest/utils': 3.0.6 1169 | pathe: 2.0.3 1170 | 1171 | '@vitest/snapshot@3.0.6': 1172 | dependencies: 1173 | '@vitest/pretty-format': 3.0.6 1174 | magic-string: 0.30.17 1175 | pathe: 2.0.3 1176 | 1177 | '@vitest/spy@3.0.6': 1178 | dependencies: 1179 | tinyspy: 3.0.2 1180 | 1181 | '@vitest/utils@3.0.6': 1182 | dependencies: 1183 | '@vitest/pretty-format': 3.0.6 1184 | loupe: 3.1.3 1185 | tinyrainbow: 2.0.0 1186 | 1187 | acorn-walk@8.3.2: {} 1188 | 1189 | acorn@8.11.3: {} 1190 | 1191 | ansi-regex@5.0.1: {} 1192 | 1193 | ansi-regex@6.0.1: {} 1194 | 1195 | ansi-styles@4.3.0: 1196 | dependencies: 1197 | color-convert: 2.0.1 1198 | 1199 | ansi-styles@6.2.1: {} 1200 | 1201 | arg@4.1.3: {} 1202 | 1203 | assertion-error@2.0.1: {} 1204 | 1205 | balanced-match@1.0.2: {} 1206 | 1207 | brace-expansion@2.0.1: 1208 | dependencies: 1209 | balanced-match: 1.0.2 1210 | 1211 | cac@6.7.14: {} 1212 | 1213 | chai@5.2.0: 1214 | dependencies: 1215 | assertion-error: 2.0.1 1216 | check-error: 2.1.1 1217 | deep-eql: 5.0.2 1218 | loupe: 3.1.1 1219 | pathval: 2.0.0 1220 | 1221 | check-error@2.1.1: {} 1222 | 1223 | color-convert@2.0.1: 1224 | dependencies: 1225 | color-name: 1.1.4 1226 | 1227 | color-name@1.1.4: {} 1228 | 1229 | create-require@1.1.1: {} 1230 | 1231 | cross-spawn@7.0.5: 1232 | dependencies: 1233 | path-key: 3.1.1 1234 | shebang-command: 2.0.0 1235 | which: 2.0.2 1236 | 1237 | debug@4.4.0: 1238 | dependencies: 1239 | ms: 2.1.3 1240 | 1241 | deep-eql@5.0.2: {} 1242 | 1243 | diff@4.0.2: {} 1244 | 1245 | eastasianwidth@0.2.0: {} 1246 | 1247 | emoji-regex@8.0.0: {} 1248 | 1249 | emoji-regex@9.2.2: {} 1250 | 1251 | es-module-lexer@1.6.0: {} 1252 | 1253 | esbuild-android-64@0.15.18: 1254 | optional: true 1255 | 1256 | esbuild-android-arm64@0.15.18: 1257 | optional: true 1258 | 1259 | esbuild-darwin-64@0.15.18: 1260 | optional: true 1261 | 1262 | esbuild-darwin-arm64@0.15.18: 1263 | optional: true 1264 | 1265 | esbuild-freebsd-64@0.15.18: 1266 | optional: true 1267 | 1268 | esbuild-freebsd-arm64@0.15.18: 1269 | optional: true 1270 | 1271 | esbuild-linux-32@0.15.18: 1272 | optional: true 1273 | 1274 | esbuild-linux-64@0.15.18: 1275 | optional: true 1276 | 1277 | esbuild-linux-arm64@0.15.18: 1278 | optional: true 1279 | 1280 | esbuild-linux-arm@0.15.18: 1281 | optional: true 1282 | 1283 | esbuild-linux-mips64le@0.15.18: 1284 | optional: true 1285 | 1286 | esbuild-linux-ppc64le@0.15.18: 1287 | optional: true 1288 | 1289 | esbuild-linux-riscv64@0.15.18: 1290 | optional: true 1291 | 1292 | esbuild-linux-s390x@0.15.18: 1293 | optional: true 1294 | 1295 | esbuild-netbsd-64@0.15.18: 1296 | optional: true 1297 | 1298 | esbuild-openbsd-64@0.15.18: 1299 | optional: true 1300 | 1301 | esbuild-sunos-64@0.15.18: 1302 | optional: true 1303 | 1304 | esbuild-windows-32@0.15.18: 1305 | optional: true 1306 | 1307 | esbuild-windows-64@0.15.18: 1308 | optional: true 1309 | 1310 | esbuild-windows-arm64@0.15.18: 1311 | optional: true 1312 | 1313 | esbuild@0.15.18: 1314 | optionalDependencies: 1315 | '@esbuild/android-arm': 0.15.18 1316 | '@esbuild/linux-loong64': 0.15.18 1317 | esbuild-android-64: 0.15.18 1318 | esbuild-android-arm64: 0.15.18 1319 | esbuild-darwin-64: 0.15.18 1320 | esbuild-darwin-arm64: 0.15.18 1321 | esbuild-freebsd-64: 0.15.18 1322 | esbuild-freebsd-arm64: 0.15.18 1323 | esbuild-linux-32: 0.15.18 1324 | esbuild-linux-64: 0.15.18 1325 | esbuild-linux-arm: 0.15.18 1326 | esbuild-linux-arm64: 0.15.18 1327 | esbuild-linux-mips64le: 0.15.18 1328 | esbuild-linux-ppc64le: 0.15.18 1329 | esbuild-linux-riscv64: 0.15.18 1330 | esbuild-linux-s390x: 0.15.18 1331 | esbuild-netbsd-64: 0.15.18 1332 | esbuild-openbsd-64: 0.15.18 1333 | esbuild-sunos-64: 0.15.18 1334 | esbuild-windows-32: 0.15.18 1335 | esbuild-windows-64: 0.15.18 1336 | esbuild-windows-arm64: 0.15.18 1337 | 1338 | esbuild@0.21.5: 1339 | optionalDependencies: 1340 | '@esbuild/aix-ppc64': 0.21.5 1341 | '@esbuild/android-arm': 0.21.5 1342 | '@esbuild/android-arm64': 0.21.5 1343 | '@esbuild/android-x64': 0.21.5 1344 | '@esbuild/darwin-arm64': 0.21.5 1345 | '@esbuild/darwin-x64': 0.21.5 1346 | '@esbuild/freebsd-arm64': 0.21.5 1347 | '@esbuild/freebsd-x64': 0.21.5 1348 | '@esbuild/linux-arm': 0.21.5 1349 | '@esbuild/linux-arm64': 0.21.5 1350 | '@esbuild/linux-ia32': 0.21.5 1351 | '@esbuild/linux-loong64': 0.21.5 1352 | '@esbuild/linux-mips64el': 0.21.5 1353 | '@esbuild/linux-ppc64': 0.21.5 1354 | '@esbuild/linux-riscv64': 0.21.5 1355 | '@esbuild/linux-s390x': 0.21.5 1356 | '@esbuild/linux-x64': 0.21.5 1357 | '@esbuild/netbsd-x64': 0.21.5 1358 | '@esbuild/openbsd-x64': 0.21.5 1359 | '@esbuild/sunos-x64': 0.21.5 1360 | '@esbuild/win32-arm64': 0.21.5 1361 | '@esbuild/win32-ia32': 0.21.5 1362 | '@esbuild/win32-x64': 0.21.5 1363 | 1364 | estree-walker@3.0.3: 1365 | dependencies: 1366 | '@types/estree': 1.0.6 1367 | 1368 | expect-type@1.1.0: {} 1369 | 1370 | foreground-child@3.2.1: 1371 | dependencies: 1372 | cross-spawn: 7.0.5 1373 | signal-exit: 4.1.0 1374 | 1375 | fsevents@2.3.3: 1376 | optional: true 1377 | 1378 | get-func-name@2.0.2: {} 1379 | 1380 | glob@10.4.5: 1381 | dependencies: 1382 | foreground-child: 3.2.1 1383 | jackspeak: 3.4.3 1384 | minimatch: 9.0.5 1385 | minipass: 7.1.2 1386 | package-json-from-dist: 1.0.0 1387 | path-scurry: 1.11.1 1388 | 1389 | has-flag@4.0.0: {} 1390 | 1391 | html-escaper@2.0.2: {} 1392 | 1393 | is-fullwidth-code-point@3.0.0: {} 1394 | 1395 | isexe@2.0.0: {} 1396 | 1397 | istanbul-lib-coverage@3.2.2: {} 1398 | 1399 | istanbul-lib-report@3.0.1: 1400 | dependencies: 1401 | istanbul-lib-coverage: 3.2.2 1402 | make-dir: 4.0.0 1403 | supports-color: 7.2.0 1404 | 1405 | istanbul-lib-source-maps@5.0.6: 1406 | dependencies: 1407 | '@jridgewell/trace-mapping': 0.3.25 1408 | debug: 4.4.0 1409 | istanbul-lib-coverage: 3.2.2 1410 | transitivePeerDependencies: 1411 | - supports-color 1412 | 1413 | istanbul-reports@3.1.7: 1414 | dependencies: 1415 | html-escaper: 2.0.2 1416 | istanbul-lib-report: 3.0.1 1417 | 1418 | jackspeak@3.4.3: 1419 | dependencies: 1420 | '@isaacs/cliui': 8.0.2 1421 | optionalDependencies: 1422 | '@pkgjs/parseargs': 0.11.0 1423 | 1424 | loupe@3.1.1: 1425 | dependencies: 1426 | get-func-name: 2.0.2 1427 | 1428 | loupe@3.1.3: {} 1429 | 1430 | lru-cache@10.4.3: {} 1431 | 1432 | lru-cache@6.0.0: 1433 | dependencies: 1434 | yallist: 4.0.0 1435 | 1436 | magic-string@0.30.17: 1437 | dependencies: 1438 | '@jridgewell/sourcemap-codec': 1.5.0 1439 | 1440 | magicast@0.3.5: 1441 | dependencies: 1442 | '@babel/parser': 7.26.9 1443 | '@babel/types': 7.26.9 1444 | source-map-js: 1.2.1 1445 | 1446 | make-dir@4.0.0: 1447 | dependencies: 1448 | semver: 7.6.0 1449 | 1450 | make-error@1.3.6: {} 1451 | 1452 | minimatch@9.0.5: 1453 | dependencies: 1454 | brace-expansion: 2.0.1 1455 | 1456 | minipass@7.1.2: {} 1457 | 1458 | ms@2.1.3: {} 1459 | 1460 | nanoid@3.3.8: {} 1461 | 1462 | package-json-from-dist@1.0.0: {} 1463 | 1464 | path-key@3.1.1: {} 1465 | 1466 | path-scurry@1.11.1: 1467 | dependencies: 1468 | lru-cache: 10.4.3 1469 | minipass: 7.1.2 1470 | 1471 | pathe@2.0.3: {} 1472 | 1473 | pathval@2.0.0: {} 1474 | 1475 | picocolors@1.1.0: {} 1476 | 1477 | postcss@8.4.47: 1478 | dependencies: 1479 | nanoid: 3.3.8 1480 | picocolors: 1.1.0 1481 | source-map-js: 1.2.1 1482 | 1483 | rollup@4.24.0: 1484 | dependencies: 1485 | '@types/estree': 1.0.6 1486 | optionalDependencies: 1487 | '@rollup/rollup-android-arm-eabi': 4.24.0 1488 | '@rollup/rollup-android-arm64': 4.24.0 1489 | '@rollup/rollup-darwin-arm64': 4.24.0 1490 | '@rollup/rollup-darwin-x64': 4.24.0 1491 | '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 1492 | '@rollup/rollup-linux-arm-musleabihf': 4.24.0 1493 | '@rollup/rollup-linux-arm64-gnu': 4.24.0 1494 | '@rollup/rollup-linux-arm64-musl': 4.24.0 1495 | '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 1496 | '@rollup/rollup-linux-riscv64-gnu': 4.24.0 1497 | '@rollup/rollup-linux-s390x-gnu': 4.24.0 1498 | '@rollup/rollup-linux-x64-gnu': 4.24.0 1499 | '@rollup/rollup-linux-x64-musl': 4.24.0 1500 | '@rollup/rollup-win32-arm64-msvc': 4.24.0 1501 | '@rollup/rollup-win32-ia32-msvc': 4.24.0 1502 | '@rollup/rollup-win32-x64-msvc': 4.24.0 1503 | fsevents: 2.3.3 1504 | 1505 | semver@7.6.0: 1506 | dependencies: 1507 | lru-cache: 6.0.0 1508 | 1509 | shebang-command@2.0.0: 1510 | dependencies: 1511 | shebang-regex: 3.0.0 1512 | 1513 | shebang-regex@3.0.0: {} 1514 | 1515 | siginfo@2.0.0: {} 1516 | 1517 | signal-exit@4.1.0: {} 1518 | 1519 | source-map-js@1.2.1: {} 1520 | 1521 | stackback@0.0.2: {} 1522 | 1523 | std-env@3.8.0: {} 1524 | 1525 | string-width@4.2.3: 1526 | dependencies: 1527 | emoji-regex: 8.0.0 1528 | is-fullwidth-code-point: 3.0.0 1529 | strip-ansi: 6.0.1 1530 | 1531 | string-width@5.1.2: 1532 | dependencies: 1533 | eastasianwidth: 0.2.0 1534 | emoji-regex: 9.2.2 1535 | strip-ansi: 7.1.0 1536 | 1537 | strip-ansi@6.0.1: 1538 | dependencies: 1539 | ansi-regex: 5.0.1 1540 | 1541 | strip-ansi@7.1.0: 1542 | dependencies: 1543 | ansi-regex: 6.0.1 1544 | 1545 | supports-color@7.2.0: 1546 | dependencies: 1547 | has-flag: 4.0.0 1548 | 1549 | test-exclude@7.0.1: 1550 | dependencies: 1551 | '@istanbuljs/schema': 0.1.3 1552 | glob: 10.4.5 1553 | minimatch: 9.0.5 1554 | 1555 | tinybench@2.9.0: {} 1556 | 1557 | tinyexec@0.3.2: {} 1558 | 1559 | tinypool@1.0.2: {} 1560 | 1561 | tinyrainbow@2.0.0: {} 1562 | 1563 | tinyspy@3.0.2: {} 1564 | 1565 | ts-node@10.9.2(@types/node@24.10.1)(typescript@5.5.3): 1566 | dependencies: 1567 | '@cspotcode/source-map-support': 0.8.1 1568 | '@tsconfig/node10': 1.0.11 1569 | '@tsconfig/node12': 1.0.11 1570 | '@tsconfig/node14': 1.0.3 1571 | '@tsconfig/node16': 1.0.4 1572 | '@types/node': 24.10.1 1573 | acorn: 8.11.3 1574 | acorn-walk: 8.3.2 1575 | arg: 4.1.3 1576 | create-require: 1.1.1 1577 | diff: 4.0.2 1578 | make-error: 1.3.6 1579 | typescript: 5.5.3 1580 | v8-compile-cache-lib: 3.0.1 1581 | yn: 3.1.1 1582 | 1583 | tsm@2.3.0: 1584 | dependencies: 1585 | esbuild: 0.15.18 1586 | 1587 | typescript@5.5.3: {} 1588 | 1589 | undici-types@7.16.0: {} 1590 | 1591 | v8-compile-cache-lib@3.0.1: {} 1592 | 1593 | vite-node@3.0.6(@types/node@24.10.1): 1594 | dependencies: 1595 | cac: 6.7.14 1596 | debug: 4.4.0 1597 | es-module-lexer: 1.6.0 1598 | pathe: 2.0.3 1599 | vite: 5.4.8(@types/node@24.10.1) 1600 | transitivePeerDependencies: 1601 | - '@types/node' 1602 | - less 1603 | - lightningcss 1604 | - sass 1605 | - sass-embedded 1606 | - stylus 1607 | - sugarss 1608 | - supports-color 1609 | - terser 1610 | 1611 | vite@5.4.8(@types/node@24.10.1): 1612 | dependencies: 1613 | esbuild: 0.21.5 1614 | postcss: 8.4.47 1615 | rollup: 4.24.0 1616 | optionalDependencies: 1617 | '@types/node': 24.10.1 1618 | fsevents: 2.3.3 1619 | 1620 | vitest@3.0.6(@types/node@24.10.1): 1621 | dependencies: 1622 | '@vitest/expect': 3.0.6 1623 | '@vitest/mocker': 3.0.6(vite@5.4.8(@types/node@24.10.1)) 1624 | '@vitest/pretty-format': 3.0.6 1625 | '@vitest/runner': 3.0.6 1626 | '@vitest/snapshot': 3.0.6 1627 | '@vitest/spy': 3.0.6 1628 | '@vitest/utils': 3.0.6 1629 | chai: 5.2.0 1630 | debug: 4.4.0 1631 | expect-type: 1.1.0 1632 | magic-string: 0.30.17 1633 | pathe: 2.0.3 1634 | std-env: 3.8.0 1635 | tinybench: 2.9.0 1636 | tinyexec: 0.3.2 1637 | tinypool: 1.0.2 1638 | tinyrainbow: 2.0.0 1639 | vite: 5.4.8(@types/node@24.10.1) 1640 | vite-node: 3.0.6(@types/node@24.10.1) 1641 | why-is-node-running: 2.3.0 1642 | optionalDependencies: 1643 | '@types/node': 24.10.1 1644 | transitivePeerDependencies: 1645 | - less 1646 | - lightningcss 1647 | - msw 1648 | - sass 1649 | - sass-embedded 1650 | - stylus 1651 | - sugarss 1652 | - supports-color 1653 | - terser 1654 | 1655 | which@2.0.2: 1656 | dependencies: 1657 | isexe: 2.0.0 1658 | 1659 | why-is-node-running@2.3.0: 1660 | dependencies: 1661 | siginfo: 2.0.0 1662 | stackback: 0.0.2 1663 | 1664 | wrap-ansi@7.0.0: 1665 | dependencies: 1666 | ansi-styles: 4.3.0 1667 | string-width: 4.2.3 1668 | strip-ansi: 6.0.1 1669 | 1670 | wrap-ansi@8.1.0: 1671 | dependencies: 1672 | ansi-styles: 6.2.1 1673 | string-width: 5.1.2 1674 | strip-ansi: 7.1.0 1675 | 1676 | yallist@4.0.0: {} 1677 | 1678 | yn@3.1.1: {} 1679 | --------------------------------------------------------------------------------