aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js')
-rw-r--r--vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js521
1 files changed, 521 insertions, 0 deletions
diff --git a/vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js b/vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js
new file mode 100644
index 0000000..d86b758
--- /dev/null
+++ b/vanilla/node_modules/@vitest/mocker/dist/chunk-mocker.js
@@ -0,0 +1,521 @@
+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.M-eThtNZ.js';
+
+/**
+* Get original stacktrace without source map support the most performant way.
+* - Create only 1 stack frame.
+* - Rewrite prepareStackTrace to bypass "support-stack-trace" (usually takes ~250ms).
+*/
+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 _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);
+};
+
+var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var intToChar = new Uint8Array(64);
+var charToInt = new Uint8Array(128);
+for (let i = 0; i < chars.length; i++) {
+ const c = chars.charCodeAt(i);
+ intToChar[i] = c;
+ charToInt[c] = i;
+}
+const CHROME_IE_STACK_REGEXP = /^\s*at .*(?:\S:\d+|\(native\))/m;
+const SAFARI_NATIVE_CODE_REGEXP = /^(?:eval@)?(?:\[native code\])?$/;
+function extractLocation(urlLike) {
+ // Fail-fast but return locations like "(native)"
+ 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);
+ urlObj.searchParams.delete("import");
+ urlObj.searchParams.delete("browserv");
+ url = urlObj.pathname + urlObj.hash + urlObj.search;
+ }
+ if (url.startsWith("/@fs/")) {
+ const isWindows = /^\/@fs\/[a-zA-Z]:\//.test(url);
+ url = url.slice(isWindows ? 5 : 4);
+ }
+ return [
+ url,
+ parts[2] || undefined,
+ parts[3] || undefined
+ ];
+}
+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");
+ }
+ // Early return for lines that don't look like Firefox/Safari stack traces
+ // Firefox/Safari stack traces must contain '@' and should have location info after it
+ if (!line.includes("@")) {
+ return null;
+ }
+ // Find the correct @ that separates function name from location
+ // For cases like '@https://@fs/path' or 'functionName@https://@fs/path'
+ // we need to find the first @ that precedes a valid location (containing :)
+ let atIndex = -1;
+ let locationPart = "";
+ let functionName;
+ // Try each @ from left to right to find the one that gives us a valid location
+ for (let i = 0; i < line.length; i++) {
+ if (line[i] === "@") {
+ const candidateLocation = line.slice(i + 1);
+ // Minimum length 3 for valid location: 1 for filename + 1 for colon + 1 for line number (e.g., "a:1")
+ if (candidateLocation.includes(":") && candidateLocation.length >= 3) {
+ atIndex = i;
+ locationPart = candidateLocation;
+ functionName = i > 0 ? line.slice(0, i) : undefined;
+ break;
+ }
+ }
+ }
+ // Validate we found a valid location with minimum length (filename:line format)
+ if (atIndex === -1 || !locationPart.includes(":") || locationPart.length < 3) {
+ return null;
+ }
+ const [url, lineNumber, columnNumber] = extractLocation(locationPart);
+ 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);
+}
+// Based on https://github.com/stacktracejs/error-stack-parser
+// Credit to stacktracejs
+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+/, "");
+ // capture and preserve the parenthesized location "(/foo/my bar.js:12:87)" in
+ // case it has spaces in it, as the string is split on \s+ later on
+ const location = sanitizedLine.match(/ (\(.+\)$)/);
+ // remove the parenthesized location from the line, if it was matched
+ sanitizedLine = location ? sanitizedLine.replace(location[0], "") : sanitizedLine;
+ // if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine
+ // because this line doesn't have function name
+ const [url, lineNumber, columnNumber] = extractLocation(location ? location[1] : sanitizedLine);
+ let method = location && sanitizedLine || "";
+ let file = url && ["eval", "<anonymous>"].includes(url) ? undefined : url;
+ if (!file || !lineNumber || !columnNumber) {
+ return null;
+ }
+ if (method.startsWith("async ")) {
+ method = method.slice(6);
+ }
+ if (file.startsWith("file://")) {
+ file = file.slice(7);
+ }
+ // normalize Windows path (\ -> /)
+ file = file.startsWith("node:") || file.startsWith("internal:") ? file : resolve(file);
+ if (method) {
+ method = method.replace(/__vite_ssr_import_\d+__\./g, "").replace(/(Object\.)?__vite_ssr_export_default__\s?/g, "");
+ }
+ return {
+ method,
+ file,
+ line: Number.parseInt(lineNumber),
+ column: Number.parseInt(columnNumber)
+ };
+}
+
+function createCompilerHints(options) {
+ const globalThisAccessor = (options === null || options === void 0 ? void 0 : options.globalThisKey) || "__vitest_mocker__";
+ function _mocker() {
+ // @ts-expect-error injected by the plugin
+ 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");
+ // if there is no message in a stack trace, use the item - 1
+ const importerStackIndex = stackArray.findIndex((stack) => {
+ return stack.includes(` at Object.${name}`) || stack.includes(`${name}@`);
+ });
+ const stack = /* @__PURE__ */ parseSingleStack(stackArray[importerStackIndex + 1]);
+ return (stack === null || stack === void 0 ? 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(data) {
+ resolve(data);
+ clearTimeout(timeout);
+ hot.off(`${event}:result`, r);
+ });
+ });
+}
+
+const { now } = Date;
+class ModuleMocker {
+ registry = new MockerRegistry();
+ queue = new Set();
+ mockedIds = new Set();
+ constructor(interceptor, rpc, createMockInstance, config) {
+ this.interceptor = interceptor;
+ this.rpc = rpc;
+ this.createMockInstance = createMockInstance;
+ this.config = config;
+ }
+ 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);
+ await 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;
+ }
+ // vite injects this helper for optimized modules, so we try to follow the same behavior
+ const m = mod.default;
+ return (m === null || m === void 0 ? 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, resolvedUrl, redirectUrl } = await this.rpc.resolveMock(rawId, importer, { mock: "auto" });
+ const mockUrl = this.resolveMockPath(cleanVersion(resolvedUrl));
+ 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, resolvedId, mockUrl, resolvedRedirect);
+ } else {
+ mock = new AutomockedModule(rawId, resolvedId, 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
+ },
+ createMockInstance: this.createMockInstance,
+ type: moduleType
+ }, object);
+ }
+ queueMock(rawId, importer, factoryOrOptions) {
+ const promise = this.rpc.resolveMock(rawId, importer, { mock: typeof factoryOrOptions === "function" ? "factory" : (factoryOrOptions === null || factoryOrOptions === void 0 ? void 0 : factoryOrOptions.spy) ? "spy" : "auto" }).then(async ({ redirectUrl, resolvedId, resolvedUrl, needsInterop, mockType }) => {
+ const mockUrl = this.resolveMockPath(cleanVersion(resolvedUrl));
+ this.mockedIds.add(resolvedId);
+ const factory = typeof factoryOrOptions === "function" ? async () => {
+ const data = await factoryOrOptions();
+ // vite wraps all external modules that have "needsInterop" in a function that
+ // merges all exports from default into the module object
+ return needsInterop ? { default: data } : data;
+ } : undefined;
+ 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, resolvedId, mockUrl, factory);
+ } else if (mockType === "autospy") {
+ module = this.registry.register("autospy", rawId, resolvedId, mockUrl);
+ } else if (mockType === "redirect") {
+ module = this.registry.register("redirect", rawId, resolvedId, mockUrl, mockRedirect);
+ } else {
+ module = this.registry.register("automock", rawId, resolvedId, 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.url));
+ 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);
+ // URL can be /file/path.js, but path is resolved to /file/path
+ 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 };