import { mockObject } from './index.js'; import { M as MockerRegistry, R as RedirectedModule, A as AutomockedModule } from './chunk-registry.js'; import { e as extname, j as join } from './chunk-pathe.ff20891b.js'; function createSimpleStackTrace(options) { const { message = "$$stack trace error", stackTraceLimit = 1 } = options || {}; const limit = Error.stackTraceLimit; const prepareStackTrace = Error.prepareStackTrace; Error.stackTraceLimit = stackTraceLimit; Error.prepareStackTrace = (e) => e.stack; const err = new Error(message); const stackTrace = err.stack || ""; Error.prepareStackTrace = prepareStackTrace; Error.stackTraceLimit = limit; return stackTrace; } const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const intToChar = new Uint8Array(64); const charToInt = new Uint8Array(128); for (let i = 0; i < chars.length; i++) { const c = chars.charCodeAt(i); intToChar[i] = c; charToInt[c] = i; } var UrlType; (function(UrlType2) { UrlType2[UrlType2["Empty"] = 1] = "Empty"; UrlType2[UrlType2["Hash"] = 2] = "Hash"; UrlType2[UrlType2["Query"] = 3] = "Query"; UrlType2[UrlType2["RelativePath"] = 4] = "RelativePath"; UrlType2[UrlType2["AbsolutePath"] = 5] = "AbsolutePath"; UrlType2[UrlType2["SchemeRelative"] = 6] = "SchemeRelative"; UrlType2[UrlType2["Absolute"] = 7] = "Absolute"; })(UrlType || (UrlType = {})); const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//; function normalizeWindowsPath(input = "") { if (!input) { return input; } return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase()); } const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/; function cwd() { if (typeof process !== "undefined" && typeof process.cwd === "function") { return process.cwd().replace(/\\/g, "/"); } return "/"; } const resolve = function(...arguments_) { arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument)); let resolvedPath = ""; let resolvedAbsolute = false; for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) { const path = index >= 0 ? arguments_[index] : cwd(); if (!path || path.length === 0) { continue; } resolvedPath = `${path}/${resolvedPath}`; resolvedAbsolute = isAbsolute(path); } resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute); if (resolvedAbsolute && !isAbsolute(resolvedPath)) { return `/${resolvedPath}`; } return resolvedPath.length > 0 ? resolvedPath : "."; }; function normalizeString(path, allowAboveRoot) { let res = ""; let lastSegmentLength = 0; let lastSlash = -1; let dots = 0; let char = null; for (let index = 0; index <= path.length; ++index) { if (index < path.length) { char = path[index]; } else if (char === "/") { break; } else { char = "/"; } if (char === "/") { if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) { if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf("/"); if (lastSlashIndex === -1) { res = ""; lastSegmentLength = 0; } else { res = res.slice(0, lastSlashIndex); lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); } lastSlash = index; dots = 0; continue; } else if (res.length > 0) { res = ""; lastSegmentLength = 0; lastSlash = index; dots = 0; continue; } } if (allowAboveRoot) { res += res.length > 0 ? "/.." : ".."; lastSegmentLength = 2; } } else { if (res.length > 0) { res += `/${path.slice(lastSlash + 1, index)}`; } else { res = path.slice(lastSlash + 1, index); } lastSegmentLength = index - lastSlash - 1; } lastSlash = index; dots = 0; } else if (char === "." && dots !== -1) { ++dots; } else { dots = -1; } } return res; } const isAbsolute = function(p) { return _IS_ABSOLUTE_RE.test(p); }; const CHROME_IE_STACK_REGEXP = /^\s*at .*(?:\S:\d+|\(native\))/m; const SAFARI_NATIVE_CODE_REGEXP = /^(?:eval@)?(?:\[native code\])?$/; function extractLocation(urlLike) { if (!urlLike.includes(":")) { return [urlLike]; } const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/; const parts = regExp.exec(urlLike.replace(/^\(|\)$/g, "")); if (!parts) { return [urlLike]; } let url = parts[1]; if (url.startsWith("async ")) { url = url.slice(6); } if (url.startsWith("http:") || url.startsWith("https:")) { const urlObj = new URL(url); url = urlObj.pathname; } if (url.startsWith("/@fs/")) { const isWindows = /^\/@fs\/[a-zA-Z]:\//.test(url); url = url.slice(isWindows ? 5 : 4); } return [url, parts[2] || void 0, parts[3] || void 0]; } function parseSingleFFOrSafariStack(raw) { let line = raw.trim(); if (SAFARI_NATIVE_CODE_REGEXP.test(line)) { return null; } if (line.includes(" > eval")) { line = line.replace( / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g, ":$1" ); } if (!line.includes("@") && !line.includes(":")) { return null; } const functionNameRegex = /((.*".+"[^@]*)?[^@]*)(@)/; const matches = line.match(functionNameRegex); const functionName = matches && matches[1] ? matches[1] : void 0; const [url, lineNumber, columnNumber] = extractLocation( line.replace(functionNameRegex, "") ); if (!url || !lineNumber || !columnNumber) { return null; } return { file: url, method: functionName || "", line: Number.parseInt(lineNumber), column: Number.parseInt(columnNumber) }; } function parseSingleStack(raw) { const line = raw.trim(); if (!CHROME_IE_STACK_REGEXP.test(line)) { return parseSingleFFOrSafariStack(line); } return parseSingleV8Stack(line); } function parseSingleV8Stack(raw) { let line = raw.trim(); if (!CHROME_IE_STACK_REGEXP.test(line)) { return null; } if (line.includes("(eval ")) { line = line.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, ""); } let sanitizedLine = line.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, ""); const location = sanitizedLine.match(/ (\(.+\)$)/); sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine; const [url, lineNumber, columnNumber] = extractLocation( location ? location[1] : sanitizedLine ); let method = location && sanitizedLine || ""; let file = url && ["eval", ""].includes(url) ? void 0 : url; if (!file || !lineNumber || !columnNumber) { return null; } if (method.startsWith("async ")) { method = method.slice(6); } if (file.startsWith("file://")) { file = file.slice(7); } file = resolve(file); if (method) { method = method.replace(/__vite_ssr_import_\d+__\./g, ""); } return { method, file, line: Number.parseInt(lineNumber), column: Number.parseInt(columnNumber) }; } function createCompilerHints(options) { const globalThisAccessor = (options == null ? void 0 : options.globalThisKey) || "__vitest_mocker__"; function _mocker() { return typeof globalThis[globalThisAccessor] !== "undefined" ? globalThis[globalThisAccessor] : new Proxy( {}, { get(_, name) { throw new Error( `Vitest mocker was not initialized in this environment. vi.${String(name)}() is forbidden.` ); } } ); } return { hoisted(factory) { if (typeof factory !== "function") { throw new TypeError( `vi.hoisted() expects a function, but received a ${typeof factory}` ); } return factory(); }, mock(path, factory) { if (typeof path !== "string") { throw new TypeError( `vi.mock() expects a string path, but received a ${typeof path}` ); } const importer = getImporter("mock"); _mocker().queueMock( path, importer, typeof factory === "function" ? () => factory( () => _mocker().importActual( path, importer ) ) : factory ); }, unmock(path) { if (typeof path !== "string") { throw new TypeError( `vi.unmock() expects a string path, but received a ${typeof path}` ); } _mocker().queueUnmock(path, getImporter("unmock")); }, doMock(path, factory) { if (typeof path !== "string") { throw new TypeError( `vi.doMock() expects a string path, but received a ${typeof path}` ); } const importer = getImporter("doMock"); _mocker().queueMock( path, importer, typeof factory === "function" ? () => factory( () => _mocker().importActual( path, importer ) ) : factory ); }, doUnmock(path) { if (typeof path !== "string") { throw new TypeError( `vi.doUnmock() expects a string path, but received a ${typeof path}` ); } _mocker().queueUnmock(path, getImporter("doUnmock")); }, async importActual(path) { return _mocker().importActual( path, getImporter("importActual") ); }, async importMock(path) { return _mocker().importMock(path, getImporter("importMock")); } }; } function getImporter(name) { const stackTrace = /* @__PURE__ */ createSimpleStackTrace({ stackTraceLimit: 5 }); const stackArray = stackTrace.split("\n"); const importerStackIndex = stackArray.findIndex((stack2) => { return stack2.includes(` at Object.${name}`) || stack2.includes(`${name}@`); }); const stack = /* @__PURE__ */ parseSingleStack(stackArray[importerStackIndex + 1]); return (stack == null ? void 0 : stack.file) || ""; } const hot = import.meta.hot || { on: warn, off: warn, send: warn }; function warn() { console.warn("Vitest mocker cannot work if Vite didn't establish WS connection."); } function rpc(event, data) { hot.send(event, data); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error(`Failed to resolve ${event} in time`)); }, 5e3); hot.on(`${event}:result`, function r(data2) { resolve(data2); clearTimeout(timeout); hot.off("vitest:mocks:resolvedId:result", r); }); }); } const { now } = Date; class ModuleMocker { constructor(interceptor, rpc, spyOn, config) { this.interceptor = interceptor; this.rpc = rpc; this.spyOn = spyOn; this.config = config; } registry = new MockerRegistry(); queue = /* @__PURE__ */ new Set(); mockedIds = /* @__PURE__ */ new Set(); async prepare() { if (!this.queue.size) { return; } await Promise.all([...this.queue.values()]); } async resolveFactoryModule(id) { const mock = this.registry.get(id); if (!mock || mock.type !== "manual") { throw new Error(`Mock ${id} wasn't registered. This is probably a Vitest error. Please, open a new issue with reproduction.`); } const result = await mock.resolve(); return result; } getFactoryModule(id) { const mock = this.registry.get(id); if (!mock || mock.type !== "manual") { throw new Error(`Mock ${id} wasn't registered. This is probably a Vitest error. Please, open a new issue with reproduction.`); } if (!mock.cache) { throw new Error(`Mock ${id} wasn't resolved. This is probably a Vitest error. Please, open a new issue with reproduction.`); } return mock.cache; } async invalidate() { const ids = Array.from(this.mockedIds); if (!ids.length) { return; } await this.rpc.invalidate(ids); this.interceptor.invalidate(); this.registry.clear(); } async importActual(id, importer) { const resolved = await this.rpc.resolveId(id, importer); if (resolved == null) { throw new Error( `[vitest] Cannot resolve "${id}" imported from "${importer}"` ); } const ext = extname(resolved.id); const url = new URL(resolved.url, location.href); const query = `_vitest_original&ext${ext}`; const actualUrl = `${url.pathname}${url.search ? `${url.search}&${query}` : `?${query}`}${url.hash}`; return this.wrapDynamicImport(() => import( /* @vite-ignore */ actualUrl )).then((mod) => { if (!resolved.optimized || typeof mod.default === "undefined") { return mod; } const m = mod.default; return (m == null ? void 0 : m.__esModule) ? m : { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m }; }); } async importMock(rawId, importer) { await this.prepare(); const { resolvedId, redirectUrl } = await this.rpc.resolveMock( rawId, importer, { mock: "auto" } ); const mockUrl = this.resolveMockPath(cleanVersion(resolvedId)); let mock = this.registry.get(mockUrl); if (!mock) { if (redirectUrl) { const resolvedRedirect = new URL(this.resolveMockPath(cleanVersion(redirectUrl)), location.href).toString(); mock = new RedirectedModule(rawId, mockUrl, resolvedRedirect); } else { mock = new AutomockedModule(rawId, mockUrl); } } if (mock.type === "manual") { return await mock.resolve(); } if (mock.type === "automock" || mock.type === "autospy") { const url = new URL(`/@id/${resolvedId}`, location.href); const query = url.search ? `${url.search}&t=${now()}` : `?t=${now()}`; const moduleObject = await import( /* @vite-ignore */ `${url.pathname}${query}&mock=${mock.type}${url.hash}` ); return this.mockObject(moduleObject, mock.type); } return import( /* @vite-ignore */ mock.redirect ); } mockObject(object, moduleType = "automock") { return mockObject({ globalConstructors: { Object, Function, Array, Map, RegExp }, spyOn: this.spyOn, type: moduleType }, object); } queueMock(rawId, importer, factoryOrOptions) { const promise = this.rpc.resolveMock(rawId, importer, { mock: typeof factoryOrOptions === "function" ? "factory" : (factoryOrOptions == null ? void 0 : factoryOrOptions.spy) ? "spy" : "auto" }).then(async ({ redirectUrl, resolvedId, needsInterop, mockType }) => { const mockUrl = this.resolveMockPath(cleanVersion(resolvedId)); this.mockedIds.add(resolvedId); const factory = typeof factoryOrOptions === "function" ? async () => { const data = await factoryOrOptions(); return needsInterop ? { default: data } : data; } : void 0; const mockRedirect = typeof redirectUrl === "string" ? new URL(this.resolveMockPath(cleanVersion(redirectUrl)), location.href).toString() : null; let module; if (mockType === "manual") { module = this.registry.register("manual", rawId, mockUrl, factory); } else if (mockType === "autospy") { module = this.registry.register("autospy", rawId, mockUrl); } else if (mockType === "redirect") { module = this.registry.register("redirect", rawId, mockUrl, mockRedirect); } else { module = this.registry.register("automock", rawId, mockUrl); } await this.interceptor.register(module); }).finally(() => { this.queue.delete(promise); }); this.queue.add(promise); } queueUnmock(id, importer) { const promise = this.rpc.resolveId(id, importer).then(async (resolved) => { if (!resolved) { return; } const mockUrl = this.resolveMockPath(cleanVersion(resolved.id)); this.mockedIds.add(resolved.id); this.registry.delete(mockUrl); await this.interceptor.delete(mockUrl); }).finally(() => { this.queue.delete(promise); }); this.queue.add(promise); } // We need to await mock registration before importing the actual module // In case there is a mocked module in the import chain wrapDynamicImport(moduleFactory) { if (typeof moduleFactory === "function") { const promise = new Promise((resolve, reject) => { this.prepare().finally(() => { moduleFactory().then(resolve, reject); }); }); return promise; } return moduleFactory; } resolveMockPath(path) { const config = this.config; const fsRoot = join("/@fs/", config.root); if (path.startsWith(config.root)) { return path.slice(config.root.length); } if (path.startsWith(fsRoot)) { return path.slice(fsRoot.length); } return path; } } const versionRegexp = /(\?|&)v=\w{8}/; function cleanVersion(url) { return url.replace(versionRegexp, ""); } export { ModuleMocker as M, createCompilerHints as c, hot as h, rpc as r };