{"version":3,"file":"index.d.cts","sources":["../src/Matchers.ts","../src/types.ts","../src/Mock.ts","../src/CalledWithFn.ts"],"sourcesContent":["type MatcherFn<T> = (actualValue: T) => boolean\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ninterface MatcherLike<T> {\n  asymmetricMatch(other: unknown): boolean\n  toString(): string\n  getExpectedType?(): string\n  toAsymmetricMatcher?(): string\n}\n\n// needs to be a class so we can instanceof\nclass Matcher<T> implements MatcherLike<T> {\n  $$typeof: symbol\n  inverse?: boolean\n\n  constructor(\n    readonly asymmetricMatch: MatcherFn<T>,\n    private readonly description: string,\n  ) {\n    this.$$typeof = Symbol.for('vi.asymmetricMatcher')\n  }\n\n  toString() {\n    return this.description\n  }\n\n  toAsymmetricMatcher() {\n    return this.description\n  }\n\n  getExpectedType() {\n    return 'undefined'\n  }\n}\n\nclass CaptorMatcher<T> {\n  $$typeof: symbol\n  public readonly asymmetricMatch: MatcherFn<T>\n  public readonly value!: T\n  public readonly values: T[] = []\n  constructor() {\n    this.$$typeof = Symbol.for('vi.asymmetricMatcher')\n\n    this.asymmetricMatch = (actualValue: T) => {\n      // @ts-expect-error value should be read-only but we need to set it\n      this.value = actualValue\n      this.values.push(actualValue)\n      return true\n    }\n  }\n\n  getExpectedType() {\n    return 'Object'\n  }\n\n  toString() {\n    return 'captor'\n  }\n\n  toAsymmetricMatcher() {\n    return 'captor'\n  }\n}\n\ninterface MatcherCreator<T, E = T> {\n  (expectedValue?: E): Matcher<T>\n}\n\ntype MatchersOrLiterals<Y extends unknown[]> = { [K in keyof Y]: MatcherLike<Y[K]> | Y[K] }\n\nconst any: MatcherCreator<unknown> = () => new Matcher(() => true, 'any()')\nconst anyBoolean: MatcherCreator<boolean> = () => new Matcher((actualValue: boolean) => typeof actualValue === 'boolean', 'anyBoolean()')\nconst anyNumber: MatcherCreator<number> = () =>\n  new Matcher((actualValue) => typeof actualValue === 'number' && !isNaN(actualValue), 'anyNumber()')\nconst anyString: MatcherCreator<string> = () => new Matcher((actualValue: string) => typeof actualValue === 'string', 'anyString()')\nconst anyFunction: MatcherCreator<CallableFunction> = () =>\n  new Matcher((actualValue: CallableFunction) => typeof actualValue === 'function', 'anyFunction()')\nconst anySymbol: MatcherCreator<symbol> = () => new Matcher((actualValue) => typeof actualValue === 'symbol', 'anySymbol()')\nconst anyObject: MatcherCreator<unknown> = () =>\n  new Matcher((actualValue) => typeof actualValue === 'object' && actualValue !== null, 'anyObject()')\n\nconst anyArray: MatcherCreator<unknown[]> = () => new Matcher((actualValue) => Array.isArray(actualValue), 'anyArray()')\nconst anyMap: MatcherCreator<Map<unknown, unknown>> = () => new Matcher((actualValue) => actualValue instanceof Map, 'anyMap()')\nconst anySet: MatcherCreator<Set<unknown>> = () => new Matcher((actualValue) => actualValue instanceof Set, 'anySet()')\nconst isA: MatcherCreator<any> = (clazz) => new Matcher((actualValue) => actualValue instanceof clazz, 'isA()')\n\nconst arrayIncludes: MatcherCreator<unknown[], unknown> = (arrayVal) =>\n  new Matcher((actualValue) => Array.isArray(actualValue) && actualValue.includes(arrayVal), 'arrayIncludes()')\nconst setHas: MatcherCreator<Set<unknown>, unknown> = (arrayVal) =>\n  new Matcher((actualValue) => anySet().asymmetricMatch(actualValue) && actualValue.has(arrayVal), 'setHas()')\nconst mapHas: MatcherCreator<Map<unknown, unknown>, unknown> = (mapVal) =>\n  new Matcher((actualValue) => anyMap().asymmetricMatch(actualValue) && actualValue.has(mapVal), 'mapHas()')\nconst objectContainsKey: MatcherCreator<Record<string, unknown>, string> = (key) =>\n  new Matcher((actualValue) => anyObject().asymmetricMatch(actualValue) && actualValue[key!] !== undefined, 'objectContainsKey()')\nconst objectContainsValue: MatcherCreator<Record<string, unknown> | ArrayLike<unknown>> = (value) =>\n  new Matcher(\n    (actualValue) => anyObject().asymmetricMatch(actualValue) && Object.values(actualValue).includes(value),\n    'objectContainsValue()',\n  )\n\nconst notNull: MatcherCreator<unknown> = () => new Matcher((actualValue) => actualValue !== null, 'notNull()')\nconst notUndefined: MatcherCreator<unknown> = () => new Matcher((actualValue) => actualValue !== undefined, 'notUndefined()')\nconst notEmpty: MatcherCreator<unknown> = () =>\n  new Matcher((actualValue) => actualValue !== null && actualValue !== undefined && actualValue !== '', 'notEmpty()')\n\nconst captor = <T>() => new CaptorMatcher<T>()\nconst matches = <T>(matcher: MatcherFn<T>) => new Matcher(matcher, 'matches()')\n\nexport {\n  Matcher,\n  CaptorMatcher,\n  any,\n  anyBoolean,\n  anyNumber,\n  anyString,\n  anyFunction,\n  anySymbol,\n  anyObject,\n  anyArray,\n  anyMap,\n  anySet,\n  isA,\n  arrayIncludes,\n  setHas,\n  mapHas,\n  objectContainsKey,\n  objectContainsValue,\n  notNull,\n  notUndefined,\n  notEmpty,\n  captor,\n  matches,\n}\nexport type { MatcherFn, MatchersOrLiterals, MatcherCreator, MatcherLike }\n","export type FallbackImplementation<Y extends any[], T> = (...args: Y) => T\n","import { calledWithFn } from './CalledWithFn'\nimport { MatchersOrLiterals } from './Matchers'\nimport { FallbackImplementation } from './types'\nimport { DeepPartial } from 'ts-essentials'\nimport { Mock, vi } from 'vitest'\n\ntype ProxiedProperty = string | number | symbol\n\ninterface GlobalConfig {\n  // ignoreProps is required when we don't want to return anything for a mock (for example, when mocking a promise).\n  ignoreProps?: ProxiedProperty[]\n}\n\nconst DEFAULT_CONFIG: GlobalConfig = {\n  ignoreProps: ['then'],\n}\n\nlet GLOBAL_CONFIG = DEFAULT_CONFIG\n\nconst VitestMockExtended = {\n  DEFAULT_CONFIG,\n  configure: (config: GlobalConfig) => {\n    // Shallow merge so they can override anything they want.\n    GLOBAL_CONFIG = { ...DEFAULT_CONFIG, ...config }\n  },\n  resetConfig: () => {\n    GLOBAL_CONFIG = DEFAULT_CONFIG\n  },\n}\n\ninterface CalledWithMock<T, Y extends any[]> extends Mock<FallbackImplementation<Y, T>> {\n  calledWith: (...args: Y | MatchersOrLiterals<Y>) => Mock<FallbackImplementation<Y, T>>\n}\n\ntype _MockProxy<T> = {\n  [K in keyof T]: T[K] extends (...args: infer A) => infer B ? T[K] & CalledWithMock<B, A> : T[K]\n}\n\ntype MockProxy<T> = _MockProxy<T> & T\n\ntype _DeepMockProxy<T> = {\n  // This supports deep mocks in the else branch\n  [K in keyof T]: T[K] extends (...args: infer A) => infer B ? T[K] & CalledWithMock<B, A> : T[K] & _DeepMockProxy<T[K]>\n}\n\n// we intersect with T here instead of on the mapped type above to\n// prevent immediate type resolution on a recursive type, this will\n// help to improve performance for deeply nested recursive mocking\n// at the same time, this intersection preserves private properties\ntype DeepMockProxy<T> = _DeepMockProxy<T> & T\n\ntype _DeepMockProxyWithFuncPropSupport<T> = {\n  // This supports deep mocks in the else branch\n  [K in keyof T]: T[K] extends (...args: infer A) => infer B ? CalledWithMock<B, A> & DeepMockProxy<T[K]> : DeepMockProxy<T[K]>\n}\n\ntype DeepMockProxyWithFuncPropSupport<T> = _DeepMockProxyWithFuncPropSupport<T> & T\n\ninterface MockOpts {\n  deep?: boolean\n  useActualToJSON?: boolean\n  fallbackMockImplementation?: (...args: any[]) => any\n}\n\nconst mockClear = (mock: MockProxy<any>) => {\n  for (const key of Object.keys(mock)) {\n    const value = mock[key]\n    if (value === null || value === undefined) {\n      continue\n    }\n\n    if (value._isMockObject) {\n      mockClear(value)\n    }\n\n    if (value._isMockFunction && 'mockClear' in value) {\n      value.mockClear()\n    }\n  }\n\n  // This is a catch for if they pass in a vi.fn()\n  if (!mock._isMockObject) {\n    return mock.mockClear()\n  }\n}\n\nconst mockReset = (mock: MockProxy<any>) => {\n  for (const key of Object.keys(mock)) {\n    if (mock[key] === null || mock[key] === undefined) {\n      continue\n    }\n\n    if (mock[key]._isMockObject) {\n      mockReset(mock[key])\n    }\n    if (mock[key]._isMockFunction) {\n      mock[key].mockReset()\n    }\n  }\n\n  // This is a catch for if they pass in a vi.fn()\n  // Worst case, we will create a vi.fn() (since this is a proxy)\n  // below in the get and call mockReset on it\n  if (!mock._isMockObject) {\n    return mock.mockReset()\n  }\n}\n\nfunction mockDeep<T>(\n  opts: {\n    funcPropSupport?: true\n    fallbackMockImplementation?: MockOpts['fallbackMockImplementation']\n  },\n  mockImplementation?: DeepPartial<T>,\n): DeepMockProxyWithFuncPropSupport<T>\nfunction mockDeep<T>(mockImplementation?: DeepPartial<T>): DeepMockProxy<T>\nfunction mockDeep(arg1: any, arg2?: any) {\n  const [opts, mockImplementation] =\n    typeof arg1 === 'object'\n      && (typeof arg1.fallbackMockImplementation === 'function' || arg1.funcPropSupport === true)\n      ? [arg1, arg2]\n      : [{}, arg1]\n  return mock(mockImplementation, { deep: true, fallbackMockImplementation: opts.fallbackMockImplementation })\n}\n\nconst overrideMockImp = (obj: DeepPartial<any>, opts?: MockOpts) => {\n  const proxy = new Proxy<MockProxy<any>>(obj, handler(opts))\n  for (const name of Object.keys(obj)) {\n    if (typeof obj[name] === 'object' && obj[name] !== null) {\n      proxy[name] = overrideMockImp(obj[name], opts)\n    } else {\n      proxy[name] = obj[name]\n    }\n  }\n\n  return proxy\n}\n\nconst handler = (opts?: MockOpts) => ({\n  ownKeys(target: MockProxy<any>) {\n    return Reflect.ownKeys(target)\n  },\n\n  set: (obj: MockProxy<any>, property: ProxiedProperty, value: any) => {\n    obj[property] = value\n    return true\n  },\n\n  get: (obj: MockProxy<any>, property: ProxiedProperty) => {\n    if (!(property in obj)) {\n      if (property === '_isMockObject' || property === '_isMockFunction') {\n        return undefined\n      }\n\n      if (GLOBAL_CONFIG.ignoreProps?.includes(property)) {\n        return undefined\n      }\n      // Jest's internal equality checking does some wierd stuff to check for iterable equality\n      if (property === Symbol.iterator) {\n        return obj[property]\n      }\n\n      if (opts?.useActualToJSON && property === 'toJSON') {\n        return JSON.stringify(obj)\n      }\n\n      // So this calls check here is totally not ideal - jest internally does a\n      // check to see if this is a spy - which we want to say no to, but blindly returning\n      // an proxy for calls results in the spy check returning true. This is another reason\n      // why deep is opt in.\n      const fn = calledWithFn({ fallbackMockImplementation: opts?.fallbackMockImplementation })\n      if (opts?.deep && property !== 'calls') {\n        obj[property] = new Proxy<MockProxy<any>>(fn, handler(opts))\n        obj[property]._isMockObject = true\n      } else {\n        obj[property] = fn\n      }\n    }\n\n    // @ts-expect-error expected type mismatch due to any\n    if (obj instanceof Date && typeof obj[property] === 'function') {\n      // @ts-expect-error expected type mismatch due to any\n      return obj[property].bind(obj)\n    }\n\n    return obj[property]\n  },\n})\n\nconst mock = <T, MockedReturn extends MockProxy<T> & T = MockProxy<T> & T>(\n  mockImplementation: DeepPartial<T> = {} as DeepPartial<T>,\n  opts?: MockOpts,\n): MockedReturn => {\n  // @ts-expect-error private\n  mockImplementation!._isMockObject = true\n  return overrideMockImp(mockImplementation, opts)\n}\n\nconst mockFn = <\n  T,\n  A extends any[] = T extends (...args: infer AReal) => any ? AReal : any[],\n  R = T extends (...args: any) => infer RReal ? RReal : any,\n>(): CalledWithMock<R, A> & T => {\n  // @ts-expect-error hard to get this type right using any\n  return calledWithFn()\n}\n\nfunction mocked<T>(obj: T, deep?: false): ReturnType<typeof mock<T>>\nfunction mocked<T>(obj: T, deep: true): ReturnType<typeof mockDeep<T>>\nfunction mocked<T>(obj: T, _deep?: boolean) {\n  return obj;\n}\n\nfunction mockedFn<T>(obj: T) {\n  return obj as ReturnType<typeof mockFn<T>>;\n}\n\nconst stub = <T extends object>(): T => {\n  return new Proxy<T>({} as T, {\n    get: (obj, property: ProxiedProperty) => {\n      if (property in obj) {\n        // @ts-expect-error expected\n        return obj[property]\n      }\n      return vi.fn()\n    },\n  })\n}\n\nexport { mock, VitestMockExtended, mockClear, mockReset, mockDeep, mockFn, stub, mocked, mockedFn }\nexport type { GlobalConfig, CalledWithMock, MockProxy, DeepMockProxy, MockOpts }\n","import { CalledWithMock } from './Mock'\nimport { Matcher, MatchersOrLiterals } from './Matchers'\nimport { FallbackImplementation } from './types'\nimport { vi, Mock } from 'vitest'\n\ninterface CalledWithStackItem<T, Y extends any[]> {\n  args: MatchersOrLiterals<Y>\n  calledWithFn: Mock<FallbackImplementation<Y, T>>\n}\n\ninterface VitestAsymmetricMatcher {\n  asymmetricMatch(...args: any[]): boolean\n}\n\nfunction isVitestAsymmetricMatcher(obj: any): obj is VitestAsymmetricMatcher {\n  return !!obj && typeof obj === 'object'\n    && 'asymmetricMatch' in obj\n    && typeof obj.asymmetricMatch === 'function'\n}\n\nconst checkCalledWith = <T, Y extends any[]>(\n  calledWithStack: CalledWithStackItem<T, Y>[],\n  actualArgs: Y,\n  fallbackMockImplementation?: FallbackImplementation<Y, T>,\n): T => {\n  const calledWithInstance = calledWithStack.find((instance) =>\n    instance.args.every((matcher, i) => {\n      if (matcher instanceof Matcher) {\n        return matcher.asymmetricMatch(actualArgs[i])\n      }\n\n      if (isVitestAsymmetricMatcher(matcher)) {\n        return matcher.asymmetricMatch(actualArgs[i])\n      }\n\n      return actualArgs[i] === matcher\n    }),\n  )\n\n  // @ts-ignore\n  return calledWithInstance\n    ? calledWithInstance.calledWithFn(...actualArgs)\n    : fallbackMockImplementation && fallbackMockImplementation(...actualArgs)\n}\n\ntype CalledWithFnArgs<Y extends any[], T> = { fallbackMockImplementation?: FallbackImplementation<Y, T> }\n\nconst calledWithFn = <T, Y extends any[]>({ fallbackMockImplementation }: CalledWithFnArgs<Y, T> = {}): CalledWithMock<T, Y> => {\n  const fn: Mock<FallbackImplementation<Y, T>> = fallbackMockImplementation ? vi.fn(fallbackMockImplementation) : vi.fn()\n  let calledWithStack: CalledWithStackItem<T, Y>[] = []\n\n    ; (fn as CalledWithMock<T, Y>).calledWith = (...args) => {\n      // We create new function to delegate any interactions (mockReturnValue etc.) to for this set of args.\n      // If that set of args is matched, we just call that vi.fn() for the result.\n      const calledWithFn: Mock<FallbackImplementation<Y, T>> = fallbackMockImplementation ? vi.fn(fallbackMockImplementation) : vi.fn()\n      const mockImplementation = fn.getMockImplementation()\n      if (\n        !mockImplementation ||\n        fn.getMockImplementation()?.name === 'implementation' ||\n        mockImplementation === fallbackMockImplementation\n      ) {\n        // Our original function gets a mock implementation which handles the matching\n        fn.mockImplementation((...args: Y) => checkCalledWith(calledWithStack, args, fallbackMockImplementation))\n        calledWithStack = []\n      }\n      calledWithStack.unshift({ args, calledWithFn })\n\n      return calledWithFn\n    }\n\n  return fn as CalledWithMock<T, Y>\n}\n\nexport { calledWithFn }\n"],"names":[],"mappings":";;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrDO;;ACIP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3CA;AACA;AACA;AACA;;;"}