aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/vitest/dist/module-evaluator.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/dist/module-evaluator.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/dist/module-evaluator.js')
-rw-r--r--vanilla/node_modules/vitest/dist/module-evaluator.js343
1 files changed, 343 insertions, 0 deletions
diff --git a/vanilla/node_modules/vitest/dist/module-evaluator.js b/vanilla/node_modules/vitest/dist/module-evaluator.js
new file mode 100644
index 0000000..0ff253b
--- /dev/null
+++ b/vanilla/node_modules/vitest/dist/module-evaluator.js
@@ -0,0 +1,343 @@
+import { isBuiltin, createRequire } from 'node:module';
+import { pathToFileURL, fileURLToPath } from 'node:url';
+import vm from 'node:vm';
+import { ssrModuleExportsKey, ssrImportMetaKey, ssrImportKey, ssrDynamicImportKey, ssrExportAllKey } from 'vite/module-runner';
+import { T as Traces } from './chunks/traces.CCmnQaNT.js';
+
+const performanceNow = performance.now.bind(performance);
+class ModuleDebug {
+ executionStack = [];
+ startCalculateModuleExecutionInfo(filename, options) {
+ const startTime = performanceNow();
+ this.executionStack.push({
+ filename,
+ startTime,
+ subImportTime: 0
+ });
+ return () => {
+ const duration = performanceNow() - startTime;
+ const currentExecution = this.executionStack.pop();
+ if (currentExecution == null) throw new Error("Execution stack is empty, this should never happen");
+ const selfTime = duration - currentExecution.subImportTime;
+ if (this.executionStack.length > 0) this.executionStack.at(-1).subImportTime += duration;
+ return {
+ startOffset: options.startOffset,
+ external: options.external,
+ importer: options.importer,
+ duration,
+ selfTime
+ };
+ };
+ }
+}
+
+const isWindows = process.platform === "win32";
+class VitestModuleEvaluator {
+ stubs = {};
+ env = createImportMetaEnvProxy();
+ vm;
+ compiledFunctionArgumentsNames;
+ compiledFunctionArgumentsValues = [];
+ primitives;
+ debug = new ModuleDebug();
+ _otel;
+ _evaluatedModules;
+ constructor(vmOptions, options = {}) {
+ this.options = options;
+ this._otel = options.traces || new Traces({ enabled: false });
+ this.vm = vmOptions;
+ this.stubs = getDefaultRequestStubs(vmOptions?.context);
+ this._evaluatedModules = options.evaluatedModules;
+ if (options.compiledFunctionArgumentsNames) this.compiledFunctionArgumentsNames = options.compiledFunctionArgumentsNames;
+ if (options.compiledFunctionArgumentsValues) this.compiledFunctionArgumentsValues = options.compiledFunctionArgumentsValues;
+ if (vmOptions) this.primitives = vm.runInContext("({ Object, Proxy, Reflect })", vmOptions.context);
+ else this.primitives = {
+ Object,
+ Proxy,
+ Reflect
+ };
+ }
+ convertIdToImportUrl(id) {
+ // TODO: vitest returns paths for external modules, but Vite returns file://
+ // REMOVE WHEN VITE 6 SUPPORT IS OVER
+ // unfortunetly, there is a bug in Vite where ID is resolved incorrectly, so we can't return files until the fix is merged
+ // https://github.com/vitejs/vite/pull/20449
+ if (!isWindows || isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id)) return id;
+ const [filepath, query] = id.split("?");
+ if (query) return `${pathToFileURL(filepath).toString()}?${query}`;
+ return pathToFileURL(filepath).toString();
+ }
+ async runExternalModule(id) {
+ if (id in this.stubs) return this.stubs[id];
+ const file = this.convertIdToImportUrl(id);
+ const importer = (this._evaluatedModules?.getModuleById(id)?.importers)?.values().next().value;
+ const filename = id.startsWith("file://") ? fileURLToPath(id) : id;
+ const finishModuleExecutionInfo = this.debug.startCalculateModuleExecutionInfo(filename, {
+ startOffset: 0,
+ external: true,
+ importer
+ });
+ const namespace = await this._otel.$("vitest.module.external", { attributes: { "code.file.path": file } }, () => this.vm ? this.vm.externalModulesExecutor.import(file) : import(file)).finally(() => {
+ this.options.moduleExecutionInfo?.set(filename, finishModuleExecutionInfo());
+ });
+ if (!this.shouldInterop(file, namespace)) return namespace;
+ const { mod, defaultExport } = interopModule(namespace);
+ const { Proxy, Reflect } = this.primitives;
+ return new Proxy(mod, {
+ get(mod, prop) {
+ if (prop === "default") return defaultExport;
+ return mod[prop] ?? defaultExport?.[prop];
+ },
+ has(mod, prop) {
+ if (prop === "default") return defaultExport !== void 0;
+ return prop in mod || defaultExport && prop in defaultExport;
+ },
+ getOwnPropertyDescriptor(mod, prop) {
+ const descriptor = Reflect.getOwnPropertyDescriptor(mod, prop);
+ if (descriptor) return descriptor;
+ if (prop === "default" && defaultExport !== void 0) return {
+ value: defaultExport,
+ enumerable: true,
+ configurable: true
+ };
+ }
+ });
+ }
+ async runInlinedModule(context, code, module) {
+ return this._otel.$("vitest.module.inline", (span) => this._runInlinedModule(context, code, module, span));
+ }
+ async _runInlinedModule(context, code, module, span) {
+ context.__vite_ssr_import_meta__.env = this.env;
+ const { Reflect, Proxy, Object } = this.primitives;
+ const exportsObject = context[ssrModuleExportsKey];
+ const SYMBOL_NOT_DEFINED = Symbol("not defined");
+ let moduleExports = SYMBOL_NOT_DEFINED;
+ // this proxy is triggered only on exports.{name} and module.exports access
+ // inside the module itself. imported module is always "exports"
+ const cjsExports = new Proxy(exportsObject, {
+ get: (target, p, receiver) => {
+ if (Reflect.has(target, p)) return Reflect.get(target, p, receiver);
+ return Reflect.get(Object.prototype, p, receiver);
+ },
+ getPrototypeOf: () => Object.prototype,
+ set: (_, p, value) => {
+ span.addEvent(`cjs export proxy is triggered for ${String(p)}`);
+ // treat "module.exports =" the same as "exports.default =" to not have nested "default.default",
+ // so "exports.default" becomes the actual module
+ if (p === "default" && this.shouldInterop(module.file, { default: value }) && cjsExports !== value) {
+ span.addEvent("`exports.default` is assigned, copying values");
+ exportAll(cjsExports, value);
+ exportsObject.default = value;
+ return true;
+ }
+ if (!Reflect.has(exportsObject, "default")) exportsObject.default = {};
+ // returns undefined, when accessing named exports, if default is not an object
+ // but is still present inside hasOwnKeys, this is Node behaviour for CJS
+ if (moduleExports !== SYMBOL_NOT_DEFINED && isPrimitive(moduleExports)) {
+ span.addEvent(`\`exports.${String(p)}\` is assigned, but module.exports is a primitive. assigning "undefined" values instead to comply with ESM`);
+ defineExport(exportsObject, p, () => void 0);
+ return true;
+ }
+ if (!isPrimitive(exportsObject.default)) exportsObject.default[p] = value;
+ if (p !== "default") defineExport(exportsObject, p, () => value);
+ return true;
+ }
+ });
+ const moduleProxy = {
+ set exports(value) {
+ span.addEvent("`module.exports` is assigned directly, copying all properties to `exports`");
+ exportAll(cjsExports, value);
+ exportsObject.default = value;
+ moduleExports = value;
+ },
+ get exports() {
+ return cjsExports;
+ }
+ };
+ const meta = context[ssrImportMetaKey];
+ if (this.options.getCurrentTestFilepath?.() === module.file) {
+ const globalNamespace = this.vm?.context || globalThis;
+ Object.defineProperty(meta, "vitest", { get: () => globalNamespace.__vitest_index__ });
+ }
+ const filename = meta.filename;
+ const dirname = meta.dirname;
+ span.setAttributes({ "code.file.path": filename });
+ const require = this.createRequire(meta.url);
+ const argumentsList = [
+ ssrModuleExportsKey,
+ ssrImportMetaKey,
+ ssrImportKey,
+ ssrDynamicImportKey,
+ ssrExportAllKey,
+ "__vite_ssr_exportName__",
+ "__filename",
+ "__dirname",
+ "module",
+ "exports",
+ "require"
+ ];
+ if (this.compiledFunctionArgumentsNames) argumentsList.push(...this.compiledFunctionArgumentsNames);
+ span.setAttribute("vitest.module.arguments", argumentsList);
+ // add 'use strict' since ESM enables it by default
+ const codeDefinition = `'use strict';async (${argumentsList.join(",")})=>{{`;
+ const wrappedCode = `${codeDefinition}${code}\n}}`;
+ const options = {
+ filename: module.id,
+ lineOffset: 0,
+ columnOffset: -codeDefinition.length
+ };
+ // this will always be 1 element because it's cached after load
+ const importer = module.importers.values().next().value;
+ const finishModuleExecutionInfo = this.debug.startCalculateModuleExecutionInfo(options.filename, {
+ startOffset: codeDefinition.length,
+ importer
+ });
+ try {
+ await (this.vm ? vm.runInContext(wrappedCode, this.vm.context, options) : vm.runInThisContext(wrappedCode, options))(
+ context[ssrModuleExportsKey],
+ context[ssrImportMetaKey],
+ context[ssrImportKey],
+ context[ssrDynamicImportKey],
+ context[ssrExportAllKey],
+ // vite 7 support, remove when vite 7+ is supported
+ context.__vite_ssr_exportName__ || ((name, getter) => Object.defineProperty(exportsObject, name, {
+ enumerable: true,
+ configurable: true,
+ get: getter
+ })),
+ filename,
+ dirname,
+ moduleProxy,
+ cjsExports,
+ require,
+ ...this.compiledFunctionArgumentsValues
+ );
+ } finally {
+ // moduleExecutionInfo needs to use Node filename instead of the normalized one
+ // because we rely on this behaviour in coverage-v8, for example
+ this.options.moduleExecutionInfo?.set(options.filename, finishModuleExecutionInfo());
+ }
+ }
+ createRequire(filename) {
+ return this.vm ? this.vm.externalModulesExecutor.createRequire(filename) : createRequire(filename);
+ }
+ shouldInterop(path, mod) {
+ if (this.options.interopDefault === false) return false;
+ // never interop ESM modules
+ // TODO: should also skip for `.js` with `type="module"`
+ return !path.endsWith(".mjs") && "default" in mod;
+ }
+}
+function createImportMetaEnvProxy() {
+ // packages/vitest/src/node/plugins/index.ts:146
+ const booleanKeys = [
+ "DEV",
+ "PROD",
+ "SSR"
+ ];
+ return new Proxy(process.env, {
+ get(_, key) {
+ if (typeof key !== "string") return;
+ if (booleanKeys.includes(key)) return !!process.env[key];
+ return process.env[key];
+ },
+ set(_, key, value) {
+ if (typeof key !== "string") return true;
+ if (booleanKeys.includes(key)) process.env[key] = value ? "1" : "";
+ else process.env[key] = value;
+ return true;
+ }
+ });
+}
+function updateStyle(id, css) {
+ if (typeof document === "undefined") return;
+ const element = document.querySelector(`[data-vite-dev-id="${id}"]`);
+ if (element) {
+ element.textContent = css;
+ return;
+ }
+ const head = document.querySelector("head");
+ const style = document.createElement("style");
+ style.setAttribute("type", "text/css");
+ style.setAttribute("data-vite-dev-id", id);
+ style.textContent = css;
+ head?.appendChild(style);
+}
+function removeStyle(id) {
+ if (typeof document === "undefined") return;
+ const sheet = document.querySelector(`[data-vite-dev-id="${id}"]`);
+ if (sheet) document.head.removeChild(sheet);
+}
+const defaultClientStub = {
+ injectQuery: (id) => id,
+ createHotContext: () => {
+ return {
+ accept: () => {},
+ prune: () => {},
+ dispose: () => {},
+ decline: () => {},
+ invalidate: () => {},
+ on: () => {},
+ send: () => {}
+ };
+ },
+ updateStyle: () => {},
+ removeStyle: () => {}
+};
+function getDefaultRequestStubs(context) {
+ if (!context) {
+ const clientStub = {
+ ...defaultClientStub,
+ updateStyle,
+ removeStyle
+ };
+ return { "/@vite/client": clientStub };
+ }
+ const clientStub = vm.runInContext(`(defaultClient) => ({ ...defaultClient, updateStyle: ${updateStyle.toString()}, removeStyle: ${removeStyle.toString()} })`, context)(defaultClientStub);
+ return { "/@vite/client": clientStub };
+}
+function exportAll(exports$1, sourceModule) {
+ // #1120 when a module exports itself it causes
+ // call stack error
+ if (exports$1 === sourceModule) return;
+ if (isPrimitive(sourceModule) || Array.isArray(sourceModule) || sourceModule instanceof Promise) return;
+ for (const key in sourceModule) if (key !== "default" && !(key in exports$1)) try {
+ defineExport(exports$1, key, () => sourceModule[key]);
+ } catch {}
+}
+// keep consistency with Vite on how exports are defined
+function defineExport(exports$1, key, value) {
+ Object.defineProperty(exports$1, key, {
+ enumerable: true,
+ configurable: true,
+ get: value
+ });
+}
+function isPrimitive(v) {
+ return !(typeof v === "object" || typeof v === "function") || v == null;
+}
+function interopModule(mod) {
+ if (isPrimitive(mod)) return {
+ mod: { default: mod },
+ defaultExport: mod
+ };
+ let defaultExport = "default" in mod ? mod.default : mod;
+ if (!isPrimitive(defaultExport) && "__esModule" in defaultExport) {
+ mod = defaultExport;
+ if ("default" in defaultExport) defaultExport = defaultExport.default;
+ }
+ return {
+ mod,
+ defaultExport
+ };
+}
+const VALID_ID_PREFIX = `/@id/`;
+const NULL_BYTE_PLACEHOLDER = `__x00__`;
+function wrapId(id) {
+ return id.startsWith(VALID_ID_PREFIX) ? id : VALID_ID_PREFIX + id.replace("\0", NULL_BYTE_PLACEHOLDER);
+}
+function unwrapId(id) {
+ return id.startsWith(VALID_ID_PREFIX) ? id.slice(VALID_ID_PREFIX.length).replace(NULL_BYTE_PLACEHOLDER, "\0") : id;
+}
+
+export { VitestModuleEvaluator, createImportMetaEnvProxy, getDefaultRequestStubs, isPrimitive, unwrapId, wrapId };