Sorry, the diff of this file is too big to display
| import { runInThisContext } from 'node:vm'; | ||
| import { s as spyModule } from './spy.B8mHA9qu.js'; | ||
| import { r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks, s as setupChaiConfig } from './index.JaztIWgW.js'; | ||
| import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.CfiYZpFg.js'; | ||
| import { Traces } from '../traces.js'; | ||
| import { V as VitestEvaluatedModules } from './rpc.iNjF664v.js'; | ||
| import { s as startVitestModuleRunner, c as createNodeImportMeta } from './index.DxR-nMjO.js'; | ||
| import { performance as performance$1 } from 'node:perf_hooks'; | ||
| import { s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from './coverage.BfSEMtie.js'; | ||
| import { i as index, g as globalExpect, v as vi } from './index.CLtI1k_4.js'; | ||
| import { c as closeInspector } from './inspector.CvyFGlXm.js'; | ||
| import { s as startTests, p as publicCollect } from './artifact.DC5WoEgy.js'; | ||
| import { createRequire } from 'node:module'; | ||
| import timers from 'node:timers'; | ||
| import timersPromises from 'node:timers/promises'; | ||
| import util from 'node:util'; | ||
| import { K as KNOWN_ASSET_TYPES } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { s as setupCommonEnv, b as setupEnv } from './setup-common.vxjAyUtK.js'; | ||
| import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.DYj33du9.js'; | ||
| // this should only be used in Node | ||
| let globalSetup = false; | ||
| async function setupGlobalEnv(config, environment) { | ||
| await setupCommonEnv(config); | ||
| Object.defineProperty(globalThis, "__vitest_index__", { | ||
| value: index, | ||
| enumerable: false | ||
| }); | ||
| globalExpect.setState({ environment: environment.name }); | ||
| if (globalSetup) return; | ||
| globalSetup = true; | ||
| if ((environment.viteEnvironment || environment.name) === "client") { | ||
| const _require = createRequire(import.meta.url); | ||
| // always mock "required" `css` files, because we cannot process them | ||
| _require.extensions[".css"] = resolveCss; | ||
| _require.extensions[".scss"] = resolveCss; | ||
| _require.extensions[".sass"] = resolveCss; | ||
| _require.extensions[".less"] = resolveCss; | ||
| // since we are using Vite, we can assume how these will be resolved | ||
| KNOWN_ASSET_TYPES.forEach((type) => { | ||
| _require.extensions[`.${type}`] = resolveAsset; | ||
| }); | ||
| process.env.SSR = ""; | ||
| } else process.env.SSR = "1"; | ||
| // @ts-expect-error not typed global for patched timers | ||
| globalThis.__vitest_required__ = { | ||
| util, | ||
| timers, | ||
| timersPromises | ||
| }; | ||
| if (!config.disableConsoleIntercept) await setupConsoleLogSpy(); | ||
| } | ||
| function resolveCss(mod) { | ||
| mod.exports = ""; | ||
| } | ||
| function resolveAsset(mod, url) { | ||
| mod.exports = url; | ||
| } | ||
| async function setupConsoleLogSpy() { | ||
| const { createCustomConsole } = await import('./console.omGxyKMT.js'); | ||
| globalThis.console = createCustomConsole(); | ||
| } | ||
| // browser shouldn't call this! | ||
| async function run(method, files, config, moduleRunner, environment, traces) { | ||
| const workerState = getWorkerState(); | ||
| const [testRunner] = await Promise.all([ | ||
| traces.$("vitest.runtime.runner", () => resolveTestRunner(config, moduleRunner, traces)), | ||
| traces.$("vitest.runtime.global_env", () => setupGlobalEnv(config, environment)), | ||
| traces.$("vitest.runtime.coverage.start", () => startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })), | ||
| traces.$("vitest.runtime.snapshot.environment", async () => { | ||
| if (!workerState.config.snapshotOptions.snapshotEnvironment) workerState.config.snapshotOptions.snapshotEnvironment = await resolveSnapshotEnvironment(config, moduleRunner); | ||
| }) | ||
| ]); | ||
| workerState.onCancel((reason) => { | ||
| closeInspector(config); | ||
| testRunner.cancel?.(reason); | ||
| }); | ||
| workerState.durations.prepare = performance$1.now() - workerState.durations.prepare; | ||
| await traces.$(`vitest.test.runner.${method}`, async () => { | ||
| for (const file of files) { | ||
| if (config.isolate) { | ||
| moduleRunner.mocker?.reset(); | ||
| resetModules(workerState.evaluatedModules, true); | ||
| } | ||
| workerState.filepath = file.filepath; | ||
| if (method === "run") { | ||
| const collectAsyncLeaks = config.detectAsyncLeaks ? detectAsyncLeaks(file.filepath, workerState.ctx.projectName) : void 0; | ||
| await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner)); | ||
| const leaks = await collectAsyncLeaks?.(); | ||
| if (leaks?.length) workerState.rpc.onAsyncLeaks(leaks); | ||
| } else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => publicCollect([file], testRunner)); | ||
| // reset after tests, because user might call `vi.setConfig` in setupFile | ||
| vi.resetConfig(); | ||
| // mocks should not affect different files | ||
| vi.restoreAllMocks(); | ||
| } | ||
| }); | ||
| await traces.$("vitest.runtime.coverage.stop", () => stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })); | ||
| } | ||
| let _moduleRunner; | ||
| const evaluatedModules = new VitestEvaluatedModules(); | ||
| const moduleExecutionInfo = /* @__PURE__ */ new Map(); | ||
| async function startModuleRunner(options) { | ||
| if (_moduleRunner) return _moduleRunner; | ||
| process.exit = (code = process.exitCode || 0) => { | ||
| throw new Error(`process.exit unexpectedly called with "${code}"`); | ||
| }; | ||
| const state = () => getSafeWorkerState() || options.state; | ||
| listenForErrors(state); | ||
| if (options.state.config.experimental.viteModuleRunner === false) { | ||
| const root = options.state.config.root; | ||
| let mocker; | ||
| if (options.state.config.experimental.nodeLoader !== false) { | ||
| // this additionally imports acorn/magic-string | ||
| const { NativeModuleMocker } = await import('./nativeModuleMocker.Uot80PXb.js'); | ||
| mocker = new NativeModuleMocker({ | ||
| async resolveId(id, importer) { | ||
| // TODO: use import.meta.resolve instead | ||
| return state().rpc.resolve(id, importer, "__vitest__"); | ||
| }, | ||
| root, | ||
| moduleDirectories: state().config.deps.moduleDirectories || ["/node_modules/"], | ||
| traces: options.traces || new Traces({ enabled: false }), | ||
| getCurrentTestFilepath() { | ||
| return state().filepath; | ||
| }, | ||
| spyModule | ||
| }); | ||
| } | ||
| // imported lazily (pulls in `local-pkg`) so it stays out of the default | ||
| // worker startup graph; only the `viteModuleRunner: false` path needs it | ||
| const { NativeModuleRunner } = await import('./nativeModuleRunner.BDnwGb8g.js').then(function (n) { return n.n; }); | ||
| _moduleRunner = new NativeModuleRunner(root, mocker); | ||
| return _moduleRunner; | ||
| } | ||
| _moduleRunner = startVitestModuleRunner(options); | ||
| return _moduleRunner; | ||
| } | ||
| let _currentEnvironment; | ||
| let _environmentTime; | ||
| /** @experimental */ | ||
| async function setupBaseEnvironment(context) { | ||
| if (context.config.experimental.viteModuleRunner === false) { | ||
| const { setupNodeLoaderHooks } = await import('./native.BUCvPRKp.js'); | ||
| await setupNodeLoaderHooks(context); | ||
| } | ||
| const startTime = performance.now(); | ||
| const { environment: { name: environmentName, options: environmentOptions }, rpc, config } = context; | ||
| setupEnv(config.env, context.metaEnv); | ||
| // we could load @vite/env, but it would take ~8ms, while this takes ~0,02ms | ||
| if (context.config.serializedDefines) try { | ||
| runInThisContext(`(() =>{\n${context.config.serializedDefines}})()`, { | ||
| lineOffset: 1, | ||
| filename: "virtual:load-defines.js" | ||
| }); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom "defines": ${error.message}`); | ||
| } | ||
| const otel = context.traces; | ||
| const { environment, loader } = await loadEnvironment(environmentName, config.root, rpc, otel, context.config.experimental.viteModuleRunner); | ||
| _currentEnvironment = environment; | ||
| const env = await otel.$("vitest.runtime.environment.setup", { attributes: { | ||
| "vitest.environment": environment.name, | ||
| "vitest.environment.vite_environment": environment.viteEnvironment || environment.name | ||
| } }, () => environment.setup(globalThis, environmentOptions || config.environmentOptions || {})); | ||
| _environmentTime = performance.now() - startTime; | ||
| if (config.chaiConfig) setupChaiConfig(config.chaiConfig); | ||
| return async () => { | ||
| await otel.$("vitest.runtime.environment.teardown", () => env.teardown(globalThis)); | ||
| await loader?.close(); | ||
| }; | ||
| } | ||
| /** @experimental */ | ||
| async function runBaseTests(method, state, traces) { | ||
| const { ctx } = state; | ||
| state.environment = _currentEnvironment; | ||
| state.durations.environment = _environmentTime; | ||
| // state has new context, but we want to reuse existing ones | ||
| state.evaluatedModules = evaluatedModules; | ||
| state.moduleExecutionInfo = moduleExecutionInfo; | ||
| provideWorkerState(globalThis, state); | ||
| if (ctx.invalidates) ctx.invalidates.forEach((filepath) => { | ||
| (state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => { | ||
| state.evaluatedModules.invalidateModule(module); | ||
| }); | ||
| }); | ||
| ctx.files.forEach((i) => { | ||
| const filepath = i.filepath; | ||
| (state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => { | ||
| state.evaluatedModules.invalidateModule(module); | ||
| }); | ||
| }); | ||
| const moduleRunner = await startModuleRunner({ | ||
| state, | ||
| evaluatedModules: state.evaluatedModules, | ||
| spyModule, | ||
| createImportMeta: createNodeImportMeta, | ||
| traces | ||
| }); | ||
| emitModuleRunner(moduleRunner); | ||
| await run(method, ctx.files, ctx.config, moduleRunner, _currentEnvironment, traces); | ||
| } | ||
| export { runBaseTests as r, setupBaseEnvironment as s }; |
| import { be as FileSpecification } from './config.d.DsC1jkby.js'; | ||
| import { O as OTELCarrier } from './rpc.d.BeasqWpO.js'; | ||
| import { T as TestExecutionMethod } from './worker.d.s_RdeZtI.js'; | ||
| type SerializedTestSpecification = [project: { | ||
| name: string | undefined; | ||
| root: string; | ||
| }, file: string, options: { | ||
| pool: string; | ||
| testLines?: number[] | undefined; | ||
| testIds?: string[] | undefined; | ||
| testNamePattern?: RegExp | undefined; | ||
| testTagsFilter?: string[] | undefined; | ||
| }]; | ||
| interface ModuleDefinitionLocation { | ||
| line: number; | ||
| column: number; | ||
| } | ||
| interface SourceModuleLocations { | ||
| modules: ModuleDefinitionDiagnostic[]; | ||
| untracked: ModuleDefinitionDiagnostic[]; | ||
| } | ||
| interface ModuleDefinitionDiagnostic { | ||
| start: ModuleDefinitionLocation; | ||
| end: ModuleDefinitionLocation; | ||
| startIndex: number; | ||
| endIndex: number; | ||
| rawUrl: string; | ||
| resolvedUrl: string; | ||
| resolvedId: string; | ||
| } | ||
| interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic { | ||
| selfTime: number; | ||
| totalTime: number; | ||
| transformTime?: number; | ||
| external?: boolean; | ||
| importer?: string; | ||
| } | ||
| interface UntrackedModuleDefinitionDiagnostic { | ||
| url: string; | ||
| resolvedId: string; | ||
| resolvedUrl: string; | ||
| selfTime: number; | ||
| totalTime: number; | ||
| transformTime?: number; | ||
| external?: boolean; | ||
| importer?: string; | ||
| } | ||
| interface SourceModuleDiagnostic { | ||
| modules: ModuleDefinitionDurationsDiagnostic[]; | ||
| untrackedModules: UntrackedModuleDefinitionDiagnostic[]; | ||
| } | ||
| interface BrowserTesterOptions { | ||
| method: TestExecutionMethod; | ||
| files: FileSpecification[]; | ||
| providedContext: string; | ||
| otelCarrier?: OTELCarrier; | ||
| concurrencyId: number; | ||
| workerId: number; | ||
| } | ||
| export type { BrowserTesterOptions as B, ModuleDefinitionDurationsDiagnostic as M, SerializedTestSpecification as S, UntrackedModuleDefinitionDiagnostic as U, ModuleDefinitionDiagnostic as a, ModuleDefinitionLocation as b, SourceModuleDiagnostic as c, SourceModuleLocations as d }; |
Sorry, the diff of this file is too big to display
| import crypto from 'node:crypto'; | ||
| function isValidApiRequest(config, req) { | ||
| const url = new URL(req.url ?? "", "http://localhost"); | ||
| // validate token. token is injected in ui/tester/orchestrator html, which is cross origin protected. | ||
| try { | ||
| const token = url.searchParams.get("token"); | ||
| if (token && crypto.timingSafeEqual(Buffer.from(token), Buffer.from(config.api.token))) return true; | ||
| } | ||
| // an error is thrown when the length is incorrect | ||
| catch {} | ||
| return false; | ||
| } | ||
| export { isValidApiRequest as i }; |
| import { mkdirSync, writeFileSync } from 'node:fs'; | ||
| import { C as CoverageProviderMap } from './coverage.BVb1JqW7.js'; | ||
| import { P as PluginHarness, L as Logger, j as VitestPackageInstaller, u as resolveConfig, V as Vitest, y as stdout, w as prompt, f as FilesNotFoundError, G as GitNotFoundError, I as IncludeTaskLocationDisabledError, z as RangeLocationFilterProvidedError, A as LocationFilterFileNotFoundError } from './index.5krd73UD.js'; | ||
| import readline from 'node:readline'; | ||
| import { y } from './tinyrainbow.Ht9iggcq.js'; | ||
| import { i as isWindows } from './env.DzFJjrmK.js'; | ||
| import { stripVTControlCharacters } from 'node:util'; | ||
| import { e as createDefer, a as relative, r as resolve, d as dirname, i as isAbsolute } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| async function createVitest(modeOrOptions, optionsOrViteOverrides = {}, viteOverridesOrVitestOptions = {}, maybeVitestOptions = {}) { | ||
| let options; | ||
| let viteOverrides; | ||
| let vitestOptions; | ||
| if (typeof modeOrOptions === "string") { | ||
| options = optionsOrViteOverrides; | ||
| viteOverrides = viteOverridesOrVitestOptions; | ||
| vitestOptions = maybeVitestOptions; | ||
| } else { | ||
| options = modeOrOptions; | ||
| viteOverrides = optionsOrViteOverrides; | ||
| vitestOptions = viteOverridesOrVitestOptions; | ||
| } | ||
| const pluginHarness = new PluginHarness(new Logger(vitestOptions.stdout, vitestOptions.stderr), vitestOptions.packageInstaller ?? new VitestPackageInstaller()); | ||
| const config = await resolveConfig(options, viteOverrides, pluginHarness); | ||
| const vitest = new Vitest(pluginHarness, config); | ||
| try { | ||
| await vitest._start(config); | ||
| if (vitest.config.api.port && vitest.config.ui && vitest.config.open) vitest.vite.openBrowser(); | ||
| return vitest; | ||
| } | ||
| // Vitest can fail at any point during setup or inside a custom plugin. | ||
| // Make sure everything is properly closed (like the logger). | ||
| catch (error) { | ||
| await vitest.close(); | ||
| throw error; | ||
| } | ||
| } | ||
| const MAX_RESULT_COUNT = 10; | ||
| const SELECTION_MAX_INDEX = 7; | ||
| const ESC = "\x1B["; | ||
| class WatchFilter { | ||
| filterRL; | ||
| currentKeyword = void 0; | ||
| message; | ||
| results = []; | ||
| selectionIndex = -1; | ||
| onKeyPress; | ||
| stdin; | ||
| stdout; | ||
| constructor(message, stdin = process.stdin, stdout$1 = stdout()) { | ||
| this.message = message; | ||
| this.stdin = stdin; | ||
| this.stdout = stdout$1; | ||
| this.filterRL = readline.createInterface({ | ||
| input: this.stdin, | ||
| escapeCodeTimeout: 50 | ||
| }); | ||
| readline.emitKeypressEvents(this.stdin, this.filterRL); | ||
| if (this.stdin.isTTY) this.stdin.setRawMode(true); | ||
| } | ||
| async filter(filterFunc) { | ||
| this.write(this.promptLine()); | ||
| const resultPromise = createDefer(); | ||
| this.onKeyPress = this.filterHandler(filterFunc, (result) => { | ||
| resultPromise.resolve(result); | ||
| }); | ||
| this.stdin.on("keypress", this.onKeyPress); | ||
| try { | ||
| return await resultPromise; | ||
| } finally { | ||
| this.close(); | ||
| } | ||
| } | ||
| filterHandler(filterFunc, onSubmit) { | ||
| return async (str, key) => { | ||
| switch (true) { | ||
| case key.sequence === "": | ||
| if (this.currentKeyword && this.currentKeyword?.length > 1) this.currentKeyword = this.currentKeyword?.slice(0, -1); | ||
| else this.currentKeyword = void 0; | ||
| break; | ||
| case key?.ctrl && key?.name === "c": | ||
| case key?.name === "escape": | ||
| this.write(`${ESC}1G${ESC}0J`); | ||
| onSubmit(void 0); | ||
| return; | ||
| case key?.name === "enter": | ||
| case key?.name === "return": { | ||
| const selection = this.results[this.selectionIndex]; | ||
| onSubmit((typeof selection === "string" ? selection : selection?.key) || this.currentKeyword || ""); | ||
| this.currentKeyword = void 0; | ||
| break; | ||
| } | ||
| case key?.name === "up": | ||
| if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--; | ||
| else this.selectionIndex = -1; | ||
| break; | ||
| case key?.name === "down": | ||
| if (this.selectionIndex < this.results.length - 1) this.selectionIndex++; | ||
| else if (this.selectionIndex >= this.results.length - 1) this.selectionIndex = this.results.length - 1; | ||
| break; | ||
| case !key?.ctrl && !key?.meta: | ||
| if (this.currentKeyword === void 0) this.currentKeyword = str; | ||
| else this.currentKeyword += str || ""; | ||
| break; | ||
| } | ||
| if (this.currentKeyword) this.results = await filterFunc(this.currentKeyword); | ||
| this.render(); | ||
| }; | ||
| } | ||
| render() { | ||
| let printStr = this.promptLine(); | ||
| if (!this.currentKeyword) printStr += "\nPlease input filter pattern"; | ||
| else if (this.currentKeyword && this.results.length === 0) printStr += "\nPattern matches no results"; | ||
| else { | ||
| const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`; | ||
| let resultBody = ""; | ||
| if (this.results.length > MAX_RESULT_COUNT) { | ||
| const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0; | ||
| const displayResults = this.results.slice(offset, MAX_RESULT_COUNT + offset); | ||
| const remainingResultCount = this.results.length - offset - displayResults.length; | ||
| resultBody = `${displayResults.map((result, index) => index + offset === this.selectionIndex ? y.green(` › ${result}`) : y.dim(` › ${result}`)).join("\n")}`; | ||
| if (remainingResultCount > 0) resultBody += ` | ||
| ${y.dim(` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}`)}`; | ||
| } else resultBody = this.results.map((result, index) => index === this.selectionIndex ? y.green(` › ${result}`) : y.dim(` › ${result}`)).join("\n"); | ||
| printStr += `\n${resultCountLine}\n${resultBody}`; | ||
| } | ||
| this.eraseAndPrint(printStr); | ||
| this.restoreCursor(); | ||
| } | ||
| keywordOffset() { | ||
| return `? ${this.message} › `.length + 1; | ||
| } | ||
| promptLine() { | ||
| return `${y.cyan("?")} ${y.bold(this.message)} › ${this.currentKeyword || ""}`; | ||
| } | ||
| eraseAndPrint(str) { | ||
| let rows = 0; | ||
| const lines = str.split(/\r?\n/); | ||
| for (const line of lines) { | ||
| const columns = "columns" in this.stdout ? this.stdout.columns : 80; | ||
| // We have to take care of screen width in case of long lines | ||
| rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns); | ||
| } | ||
| this.write(`${ESC}1G`); | ||
| this.write(`${ESC}J`); | ||
| this.write(str); | ||
| this.write(`${ESC}${rows - 1}A`); | ||
| } | ||
| close() { | ||
| this.filterRL.close(); | ||
| if (this.onKeyPress) this.stdin.removeListener("keypress", this.onKeyPress); | ||
| if (this.stdin.isTTY) this.stdin.setRawMode(false); | ||
| } | ||
| restoreCursor() { | ||
| const cursorPos = this.keywordOffset() + (this.currentKeyword?.length || 0); | ||
| this.write(`${ESC}${cursorPos}G`); | ||
| } | ||
| write(data) { | ||
| this.stdout.write(data); | ||
| } | ||
| getLastResults() { | ||
| return this.results.map((r) => typeof r === "string" ? r : r.toString()); | ||
| } | ||
| } | ||
| const keys = [ | ||
| [["a", "return"], "rerun all tests"], | ||
| ["r", "rerun current pattern tests"], | ||
| ["f", "rerun only failed tests"], | ||
| ["u", "update snapshot"], | ||
| ["p", "filter by a filename"], | ||
| ["t", "filter by a test name regex pattern"], | ||
| ["w", "filter by a project name"], | ||
| ["q", "quit"] | ||
| ]; | ||
| const cancelKeys = [ | ||
| "space", | ||
| "c", | ||
| "h", | ||
| ...keys.map((key) => key[0]).flat() | ||
| ]; | ||
| function printShortcutsHelp() { | ||
| stdout().write(` | ||
| ${y.bold(" Watch Usage")} | ||
| ${keys.map((i) => y.dim(" press ") + y.reset([i[0]].flat().map(y.bold).join(", ")) + y.dim(` to ${i[1]}`)).join("\n")} | ||
| `); | ||
| } | ||
| function* traverseFilteredTestNames(parentName, filter, t) { | ||
| if (t.type === "test") { | ||
| if (t.name.match(filter)) { | ||
| const displayName = `${parentName} > ${t.name}`; | ||
| yield { | ||
| key: t.name, | ||
| toString: () => displayName | ||
| }; | ||
| } | ||
| } else { | ||
| parentName = parentName.length ? `${parentName} > ${t.name}` : t.name; | ||
| for (const task of t.tasks) yield* traverseFilteredTestNames(parentName, filter, task); | ||
| } | ||
| } | ||
| function* getFilteredTestNames(pattern, suite) { | ||
| try { | ||
| const reg = new RegExp(pattern); | ||
| // TODO: we cannot run tests per workspace yet: filtering files | ||
| const files = /* @__PURE__ */ new Set(); | ||
| for (const file of suite) if (!files.has(file.name)) { | ||
| files.add(file.name); | ||
| yield* traverseFilteredTestNames("", reg, file); | ||
| } | ||
| } catch {} | ||
| } | ||
| function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout) { | ||
| let latestFilename = ""; | ||
| async function _keypressHandler(str, key) { | ||
| // Cancel run and exit when ctrl-c or esc is pressed. | ||
| // If cancelling takes long and key is pressed multiple times, exit forcefully. | ||
| if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") { | ||
| if (!ctx.isCancelling) { | ||
| ctx.logger.log(y.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n")); | ||
| process.exitCode = 130; | ||
| await ctx.cancelCurrentRun("keyboard-input"); | ||
| } | ||
| return ctx.exit(true); | ||
| } | ||
| // window not support suspend | ||
| if (!isWindows && key && key.ctrl && key.name === "z") { | ||
| process.kill(process.ppid, "SIGTSTP"); | ||
| process.kill(process.pid, "SIGTSTP"); | ||
| return; | ||
| } | ||
| const name = key?.name; | ||
| if (ctx.runningPromise) { | ||
| if (cancelKeys.includes(name)) await ctx.cancelCurrentRun("keyboard-input"); | ||
| return; | ||
| } | ||
| // quit | ||
| if (name === "q") return ctx.exit(true); | ||
| // help | ||
| if (name === "h") return printShortcutsHelp(); | ||
| // update snapshot | ||
| if (name === "u") return ctx.updateSnapshot(); | ||
| // rerun all tests | ||
| if (name === "a" || name === "return") { | ||
| const files = await ctx._globTestFilepaths(); | ||
| return ctx.changeNamePattern("", files, "rerun all tests"); | ||
| } | ||
| // rerun current pattern tests | ||
| if (name === "r") return ctx.rerunFiles(); | ||
| // rerun only failed tests | ||
| if (name === "f") return ctx.rerunFailed(); | ||
| // change project filter | ||
| if (name === "w") return inputProjectName(); | ||
| // change testNamePattern | ||
| if (name === "t") return inputNamePattern(); | ||
| // change fileNamePattern | ||
| if (name === "p") return inputFilePattern(); | ||
| } | ||
| async function keypressHandler(str, key) { | ||
| await _keypressHandler(str, key); | ||
| } | ||
| async function inputNamePattern() { | ||
| off(); | ||
| const filter = await new WatchFilter("Input test name pattern (RegExp)", stdin, stdout).filter((str) => { | ||
| return [...getFilteredTestNames(str, ctx.state.getFiles())]; | ||
| }); | ||
| on(); | ||
| if (typeof filter === "undefined") return; | ||
| const files = ctx.state.getFilepaths(); | ||
| // if running in standalone mode, Vitest instance doesn't know about any test file | ||
| const cliFiles = ctx.config.standalone && !files.length ? await ctx._globTestFilepaths() : void 0; | ||
| await ctx.changeNamePattern(filter?.trim() || "", cliFiles, "change pattern"); | ||
| } | ||
| async function inputProjectName() { | ||
| off(); | ||
| const { filter = "" } = await prompt([{ | ||
| name: "filter", | ||
| type: "text", | ||
| message: "Input a single project name", | ||
| initial: ctx.config.project[0] || "" | ||
| }]); | ||
| on(); | ||
| await ctx.changeProjectName(filter.trim()); | ||
| } | ||
| async function inputFilePattern() { | ||
| off(); | ||
| const watchFilter = new WatchFilter("Input filename pattern", stdin, stdout); | ||
| const filter = await watchFilter.filter(async (str) => { | ||
| return (await ctx.globTestSpecifications([str])).map((specification) => relative(ctx.config.root, specification.moduleId)).filter((file, index, all) => all.indexOf(file) === index); | ||
| }); | ||
| on(); | ||
| if (typeof filter === "undefined") return; | ||
| latestFilename = filter?.trim() || ""; | ||
| const lastResults = watchFilter.getLastResults(); | ||
| await ctx.changeFilenamePattern(latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0); | ||
| } | ||
| let rl; | ||
| function on() { | ||
| off(); | ||
| rl = readline.createInterface({ | ||
| input: stdin, | ||
| escapeCodeTimeout: 50 | ||
| }); | ||
| readline.emitKeypressEvents(stdin, rl); | ||
| if (stdin.isTTY) stdin.setRawMode(true); | ||
| stdin.on("keypress", keypressHandler); | ||
| } | ||
| function off() { | ||
| rl?.close(); | ||
| rl = void 0; | ||
| stdin.removeListener("keypress", keypressHandler); | ||
| if (stdin.isTTY) stdin.setRawMode(false); | ||
| } | ||
| on(); | ||
| return function cleanup() { | ||
| off(); | ||
| }; | ||
| } | ||
| async function startVitest(modeOrCliFilters, cliFiltersOrOptions, optionsOrViteOverrides, viteOverridesOrVitestOptions, maybeVitestOptions) { | ||
| let cliFilters; | ||
| let options; | ||
| let viteOverrides; | ||
| let vitestOptions; | ||
| if (typeof modeOrCliFilters === "string") { | ||
| cliFilters = cliFiltersOrOptions ?? []; | ||
| options = optionsOrViteOverrides ?? {}; | ||
| viteOverrides = viteOverridesOrVitestOptions; | ||
| vitestOptions = maybeVitestOptions; | ||
| } else { | ||
| cliFilters = modeOrCliFilters ?? []; | ||
| options = cliFiltersOrOptions ?? {}; | ||
| viteOverrides = optionsOrViteOverrides; | ||
| vitestOptions = viteOverridesOrVitestOptions; | ||
| } | ||
| const root = resolve(options.root || process.cwd()); | ||
| const ctx = await prepareVitest(options, viteOverrides, vitestOptions, cliFilters); | ||
| if (ctx._coverageOptions.enabled) { | ||
| const requiredPackages = CoverageProviderMap[ctx._coverageOptions.provider || "v8"]; | ||
| if (requiredPackages) { | ||
| if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) { | ||
| process.exitCode = 1; | ||
| return ctx; | ||
| } | ||
| } | ||
| } | ||
| const stdin = vitestOptions?.stdin || process.stdin; | ||
| const stdout = vitestOptions?.stdout || process.stdout; | ||
| let stdinCleanup; | ||
| if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout); | ||
| ctx.onAfterSetServer(() => { | ||
| if (ctx.config.standalone) ctx.standalone(); | ||
| else ctx.start(cliFilters); | ||
| }); | ||
| try { | ||
| if (ctx.config.listTags) await ctx.listTags(); | ||
| else if (ctx.config.clearCache) await ctx.experimental_clearCache(); | ||
| else if (ctx.config.mergeReports) await ctx.mergeReports(); | ||
| else if (ctx.config.standalone) await ctx.standalone(); | ||
| else await ctx.start(cliFilters); | ||
| return ctx; | ||
| } catch (e) { | ||
| if (e instanceof FilesNotFoundError) return ctx; | ||
| if (e instanceof GitNotFoundError) { | ||
| ctx.logger.error(e.message); | ||
| return ctx; | ||
| } | ||
| if (e instanceof IncludeTaskLocationDisabledError || e instanceof RangeLocationFilterProvidedError || e instanceof LocationFilterFileNotFoundError) { | ||
| ctx.logger.printError(e, { verbose: false }); | ||
| return ctx; | ||
| } | ||
| process.exitCode = 1; | ||
| ctx.logger.printError(e, { | ||
| fullStack: true, | ||
| type: "Unhandled Error" | ||
| }); | ||
| ctx.logger.error("\n\n"); | ||
| return ctx; | ||
| } finally { | ||
| if (!ctx?.shouldKeepServer()) { | ||
| stdinCleanup?.(); | ||
| await ctx.close(); | ||
| } | ||
| } | ||
| } | ||
| async function prepareVitest(modeOrOptions, optionsOrViteOverrides, viteOverridesOrVitestOptions, vitestOptionsOrCliFilters, maybeCliFilters) { | ||
| let options; | ||
| let viteOverrides; | ||
| let vitestOptions; | ||
| let cliFilters; | ||
| if (typeof modeOrOptions === "string") { | ||
| options = optionsOrViteOverrides ?? {}; | ||
| viteOverrides = viteOverridesOrVitestOptions; | ||
| vitestOptions = vitestOptionsOrCliFilters; | ||
| cliFilters = maybeCliFilters; | ||
| } else { | ||
| options = modeOrOptions ?? {}; | ||
| viteOverrides = optionsOrViteOverrides; | ||
| vitestOptions = viteOverridesOrVitestOptions; | ||
| cliFilters = vitestOptionsOrCliFilters; | ||
| } | ||
| process.env.TEST = "true"; | ||
| process.env.VITEST = "true"; | ||
| process.env.NODE_ENV ??= "test"; | ||
| if (options.run) options.watch = false; | ||
| if (options.standalone && (cliFilters?.length || 0) > 0) options.standalone = false; | ||
| // this shouldn't affect _application root_ that can be changed inside config | ||
| const root = resolve(options.root || process.cwd()); | ||
| const ctx = await createVitest(options, viteOverrides, vitestOptions); | ||
| const environmentPackage = getEnvPackageName(ctx.config.environment); | ||
| if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) { | ||
| process.exitCode = 1; | ||
| return ctx; | ||
| } | ||
| return ctx; | ||
| } | ||
| function processCollected(ctx, files, options) { | ||
| let errorsPrinted = false; | ||
| forEachSuite(files, (suite) => { | ||
| suite.errors().forEach((error) => { | ||
| errorsPrinted = true; | ||
| ctx.logger.printError(error, { project: suite.project }); | ||
| }); | ||
| }); | ||
| if (errorsPrinted) return; | ||
| if (typeof options.json !== "undefined") return processJsonOutput(files, options); | ||
| return formatCollectedAsString(files).forEach((test) => console.log(test)); | ||
| } | ||
| function outputFileList(files, options) { | ||
| if (typeof options.json !== "undefined") return outputJsonFileList(files, options); | ||
| formatFilesAsString(files, options).map((file) => console.log(file)); | ||
| } | ||
| function outputJsonFileList(files, options) { | ||
| if (typeof options.json === "boolean") return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2)); | ||
| if (typeof options.json === "string") { | ||
| const jsonPath = resolve(options.root || process.cwd(), options.json); | ||
| mkdirSync(dirname(jsonPath), { recursive: true }); | ||
| writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2)); | ||
| } | ||
| } | ||
| function formatFilesAsJSON(files) { | ||
| return files.map((file) => { | ||
| const result = { file: file.moduleId }; | ||
| if (file.project.name) result.projectName = file.project.name; | ||
| return result; | ||
| }); | ||
| } | ||
| function formatFilesAsString(files, options) { | ||
| return files.map((file) => { | ||
| let name = relative(options.root || process.cwd(), file.moduleId); | ||
| if (file.project.name) name = `[${file.project.name}] ${name}`; | ||
| return name; | ||
| }); | ||
| } | ||
| function processJsonOutput(files, options) { | ||
| if (typeof options.json === "boolean") return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2)); | ||
| if (typeof options.json === "string") { | ||
| const jsonPath = resolve(options.root || process.cwd(), options.json); | ||
| mkdirSync(dirname(jsonPath), { recursive: true }); | ||
| writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2)); | ||
| } | ||
| } | ||
| function forEachSuite(modules, callback) { | ||
| modules.forEach((testModule) => { | ||
| callback(testModule); | ||
| for (const suite of testModule.children.allSuites()) callback(suite); | ||
| }); | ||
| } | ||
| function formatCollectedAsJSON(files) { | ||
| const results = []; | ||
| files.forEach((file) => { | ||
| for (const test of file.children.allTests()) { | ||
| if (test.result().state === "skipped") continue; | ||
| const result = { | ||
| name: test.fullName, | ||
| file: test.module.moduleId | ||
| }; | ||
| if (test.project.name) result.projectName = test.project.name; | ||
| if (test.location) result.location = test.location; | ||
| results.push(result); | ||
| } | ||
| }); | ||
| return results; | ||
| } | ||
| function formatCollectedAsString(testModules) { | ||
| const results = []; | ||
| testModules.forEach((testModule) => { | ||
| for (const test of testModule.children.allTests()) { | ||
| if (test.result().state === "skipped") continue; | ||
| const fullName = `${test.module.task.name} > ${test.fullName}`; | ||
| results.push((test.project.name ? `[${test.project.name}] ` : "") + fullName); | ||
| } | ||
| }); | ||
| return results; | ||
| } | ||
| const envPackageNames = { | ||
| "jsdom": "jsdom", | ||
| "happy-dom": "happy-dom", | ||
| "edge-runtime": "@edge-runtime/vm" | ||
| }; | ||
| function getEnvPackageName(env) { | ||
| if (env === "node") return null; | ||
| if (env in envPackageNames) return envPackageNames[env]; | ||
| if (env[0] === "." || isAbsolute(env)) return null; | ||
| return `vitest-environment-${env}`; | ||
| } | ||
| var cliApi = /*#__PURE__*/Object.freeze({ | ||
| __proto__: null, | ||
| formatCollectedAsJSON: formatCollectedAsJSON, | ||
| formatCollectedAsString: formatCollectedAsString, | ||
| outputFileList: outputFileList, | ||
| prepareVitest: prepareVitest, | ||
| processCollected: processCollected, | ||
| startVitest: startVitest | ||
| }); | ||
| export { cliApi as a, createVitest as c, registerConsoleShortcuts as r, startVitest as s }; |
Sorry, the diff of this file is too big to display
| import { Console } from 'node:console'; | ||
| import { relative } from 'node:path'; | ||
| import { Writable } from 'node:stream'; | ||
| import { a as getSafeTimers } from './source-map.DZdIqpIJ.js'; | ||
| import { y } from './tinyrainbow.Ht9iggcq.js'; | ||
| import { R as RealDate } from './rpc.iNjF664v.js'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import 'vite/module-runner'; | ||
| import './index.Chj8NDwU.js'; | ||
| const UNKNOWN_TEST_ID = "__vitest__unknown_test__"; | ||
| function getTaskIdByStack(root) { | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE_ERROR")).stack?.split("\n"); | ||
| if (!stack) return UNKNOWN_TEST_ID; | ||
| const index = stack.findIndex((line) => line.includes("at Console.value")); | ||
| const line = index === -1 ? null : stack[index + 2]; | ||
| if (!line) return UNKNOWN_TEST_ID; | ||
| const filepath = line.match(/at\s(.*)\s?/)?.[1]; | ||
| if (filepath) return relative(root, filepath); | ||
| return UNKNOWN_TEST_ID; | ||
| } | ||
| function createCustomConsole(defaultState) { | ||
| const stdoutBuffer = /* @__PURE__ */ new Map(); | ||
| const stderrBuffer = /* @__PURE__ */ new Map(); | ||
| const timers = /* @__PURE__ */ new Map(); | ||
| const { queueMicrotask } = getSafeTimers(); | ||
| function queueCancelableMicrotask(callback) { | ||
| let canceled = false; | ||
| queueMicrotask(() => { | ||
| if (!canceled) callback(); | ||
| }); | ||
| return () => { | ||
| canceled = true; | ||
| }; | ||
| } | ||
| const state = () => defaultState || getWorkerState(); | ||
| // group sync console.log calls with micro task | ||
| function schedule(taskId) { | ||
| const timer = timers.get(taskId); | ||
| const { stdoutTime, stderrTime } = timer; | ||
| timer.cancel?.(); | ||
| timer.cancel = queueCancelableMicrotask(() => { | ||
| if (stderrTime < stdoutTime) { | ||
| sendStderr(taskId); | ||
| sendStdout(taskId); | ||
| } else { | ||
| sendStdout(taskId); | ||
| sendStderr(taskId); | ||
| } | ||
| }); | ||
| } | ||
| function sendStdout(taskId) { | ||
| sendBuffer("stdout", taskId); | ||
| } | ||
| function sendStderr(taskId) { | ||
| sendBuffer("stderr", taskId); | ||
| } | ||
| function sendBuffer(type, taskId) { | ||
| const buffers = type === "stdout" ? stdoutBuffer : stderrBuffer; | ||
| const buffer = buffers.get(taskId); | ||
| if (!buffer) return; | ||
| if (state().config.printConsoleTrace) buffer.forEach(([buffer, origin]) => { | ||
| sendLog(type, taskId, String(buffer), buffer.length, origin); | ||
| }); | ||
| else sendLog(type, taskId, buffer.map((i) => String(i[0])).join(""), buffer.length); | ||
| const timer = timers.get(taskId); | ||
| buffers.delete(taskId); | ||
| if (type === "stderr") timer.stderrTime = 0; | ||
| else timer.stdoutTime = 0; | ||
| } | ||
| function sendLog(type, taskId, content, size, origin) { | ||
| const timer = timers.get(taskId); | ||
| const time = type === "stderr" ? timer.stderrTime : timer.stdoutTime; | ||
| state().rpc.onUserConsoleLog({ | ||
| type, | ||
| content: content || "<empty line>", | ||
| taskId, | ||
| time: time || RealDate.now(), | ||
| size, | ||
| origin | ||
| }); | ||
| } | ||
| return new Console({ | ||
| stdout: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stdoutTime = timer.stdoutTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stdoutTime: RealDate.now(), | ||
| stderrTime: 0 | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stdoutBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stdoutBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const trace = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n").slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| stderr: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stderrTime = timer.stderrTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stderrTime: RealDate.now(), | ||
| stdoutTime: 0 | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stderrBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stderrBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| if (stack?.some((line) => line.includes("at Console.trace"))) buffer.push([data, void 0]); | ||
| else { | ||
| const trace = stack?.slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| colorMode: y.isColorSupported, | ||
| groupIndentation: 2 | ||
| }); | ||
| } | ||
| export { UNKNOWN_TEST_ID, createCustomConsole }; |
| import { r as resolveCoverageProviderModule } from './coverage.BVb1JqW7.js'; | ||
| async function startCoverageInsideWorker(options, loader, runtimeOptions) { | ||
| const coverageModule = await resolveCoverageProviderModule(options, loader); | ||
| if (coverageModule) return coverageModule.startCoverage?.({ | ||
| ...runtimeOptions, | ||
| autoAttachSubprocess: options.autoAttachSubprocess, | ||
| reportsDirectory: options.reportsDirectory | ||
| }); | ||
| return null; | ||
| } | ||
| async function takeCoverageInsideWorker(options, loader) { | ||
| const coverageModule = await resolveCoverageProviderModule(options, loader); | ||
| if (coverageModule) return coverageModule.takeCoverage?.({ | ||
| moduleExecutionInfo: loader.moduleExecutionInfo, | ||
| coverageFilesDirectory: options.coverageFilesDirectory | ||
| }); | ||
| return null; | ||
| } | ||
| async function stopCoverageInsideWorker(options, loader, runtimeOptions) { | ||
| const coverageModule = await resolveCoverageProviderModule(options, loader); | ||
| if (coverageModule) return coverageModule.stopCoverage?.(runtimeOptions); | ||
| return null; | ||
| } | ||
| export { stopCoverageInsideWorker as a, startCoverageInsideWorker as s, takeCoverageInsideWorker as t }; |
| import { r as resolve } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| function getCoverageFilesDirectory(reportsDirectory, shard) { | ||
| return resolve(reportsDirectory, `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`); | ||
| } | ||
| const CoverageProviderMap = { | ||
| v8: "@vitest/coverage-v8", | ||
| istanbul: "@vitest/coverage-istanbul" | ||
| }; | ||
| async function resolveCoverageProviderModule(options, loader) { | ||
| if (!options?.enabled || !options.provider) return null; | ||
| const provider = options.provider; | ||
| if (provider === "v8" || provider === "istanbul") { | ||
| let builtInModule = CoverageProviderMap[provider]; | ||
| if (loader.isBrowser) builtInModule += "/browser"; | ||
| const { default: coverageModule } = loader.isBrowser ? await loader.import(builtInModule) : await import( | ||
| /* @vite-ignore */ | ||
| builtInModule | ||
| ); | ||
| if (!coverageModule) throw new Error(`Failed to load ${CoverageProviderMap[provider]}. Default export is missing.`); | ||
| return coverageModule; | ||
| } | ||
| let customProviderModule; | ||
| try { | ||
| customProviderModule = await loader.import(options.customProviderModule); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom CoverageProviderModule from ${options.customProviderModule}`, { cause: error }); | ||
| } | ||
| if (customProviderModule.default == null) throw new Error(`Custom CoverageProviderModule loaded from ${options.customProviderModule} was not the default export`); | ||
| return customProviderModule.default; | ||
| } | ||
| export { CoverageProviderMap as C, getCoverageFilesDirectory as g, resolveCoverageProviderModule as r }; |
| import { aU as TestError, au as ParsedStack } from './config.d.DsC1jkby.js'; | ||
| type OriginalMapping = { | ||
| source: string | null; | ||
| line: number; | ||
| column: number; | ||
| name: string | null; | ||
| }; | ||
| interface StackTraceParserOptions { | ||
| ignoreStackEntries?: (RegExp | string)[]; | ||
| getSourceMap?: (file: string) => unknown; | ||
| getUrlId?: (id: string) => string; | ||
| frameFilter?: (error: TestError, frame: ParsedStack) => boolean | void; | ||
| } | ||
| interface SourceMapLike { | ||
| version: number; | ||
| mappings?: string; | ||
| names?: string[]; | ||
| sources?: string[]; | ||
| sourcesContent?: string[]; | ||
| sourceRoot?: string; | ||
| } | ||
| interface Needle { | ||
| line: number; | ||
| column: number; | ||
| } | ||
| declare class DecodedMap { | ||
| map: SourceMapLike; | ||
| _encoded: string; | ||
| _decoded: undefined | number[][][]; | ||
| _decodedMemo: Stats; | ||
| url: string; | ||
| version: number; | ||
| names: string[]; | ||
| resolvedSources: string[]; | ||
| constructor(map: SourceMapLike, from: string); | ||
| } | ||
| interface Stats { | ||
| lastKey: number; | ||
| lastNeedle: number; | ||
| lastIndex: number; | ||
| } | ||
| declare function getOriginalPosition(map: DecodedMap, needle: Needle): OriginalMapping | null; | ||
| interface RuntimeCoverageModuleLoader { | ||
| import: (id: string) => Promise<{ | ||
| default: RuntimeCoverageProviderModule; | ||
| }>; | ||
| isBrowser?: boolean; | ||
| moduleExecutionInfo?: Map<string, { | ||
| startOffset: number; | ||
| }>; | ||
| } | ||
| interface RuntimeCoverageProviderModule { | ||
| /** | ||
| * Factory for creating a new coverage provider | ||
| */ | ||
| getProvider: () => any; | ||
| /** | ||
| * Executed before tests are run in the worker thread. | ||
| */ | ||
| startCoverage?: (runtimeOptions: { | ||
| isolate: boolean; | ||
| /** @internal */ | ||
| autoAttachSubprocess: boolean; | ||
| /** @internal */ | ||
| reportsDirectory: string; | ||
| }) => unknown | Promise<unknown>; | ||
| /** | ||
| * Executed on after each run in the worker thread. Possible to return a payload passed to the provider | ||
| */ | ||
| takeCoverage?: (runtimeOptions?: { | ||
| moduleExecutionInfo?: Map<string, { | ||
| startOffset: number; | ||
| }>; | ||
| coverageFilesDirectory: string; | ||
| }) => unknown | Promise<unknown>; | ||
| /** | ||
| * Executed after all tests have been run in the worker thread. | ||
| */ | ||
| stopCoverage?: (runtimeOptions: { | ||
| isolate: boolean; | ||
| }) => unknown | Promise<unknown>; | ||
| } | ||
| export { DecodedMap as D, getOriginalPosition as g }; | ||
| export type { RuntimeCoverageModuleLoader as R, StackTraceParserOptions as S, RuntimeCoverageProviderModule as a }; |
| import { existsSync, writeFileSync, readFileSync } from 'node:fs'; | ||
| import { mkdir, writeFile } from 'node:fs/promises'; | ||
| import { resolve, dirname, relative } from 'node:path'; | ||
| import { detectPackageManager, installPackage } from './index.CMESou6r.js'; | ||
| import { w as prompt, x as findConfigFile } from './index.5krd73UD.js'; | ||
| import { x } from 'tinyexec'; | ||
| import { y } from './tinyrainbow.Ht9iggcq.js'; | ||
| import 'node:process'; | ||
| import 'node:os'; | ||
| import './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import './source-map.DZdIqpIJ.js'; | ||
| import './cac.B41kXwyU.js'; | ||
| import 'events'; | ||
| import './env.DzFJjrmK.js'; | ||
| import 'std-env'; | ||
| import './constants.-juJ8b_4.js'; | ||
| import 'node:assert'; | ||
| import '../path.js'; | ||
| import 'node:url'; | ||
| import './artifact.DC5WoEgy.js'; | ||
| import './index.DzTmMrSM.js'; | ||
| import './display.CYwyMF4S.js'; | ||
| import '../task-utils.js'; | ||
| import './nativeModuleRunner.BDnwGb8g.js'; | ||
| import 'node:module'; | ||
| import 'node:v8'; | ||
| import 'node:util'; | ||
| import 'vite/module-runner'; | ||
| import '../traces.js'; | ||
| import 'vite'; | ||
| import 'obug'; | ||
| import 'node:crypto'; | ||
| import 'tinyglobby'; | ||
| import './defaults.BJUmAuaO.js'; | ||
| import 'magic-string'; | ||
| import '@vitest/mocker/node'; | ||
| import 'node:console'; | ||
| import 'node:stream'; | ||
| import 'node:perf_hooks'; | ||
| import './offset.Dy-5Fdfn.js'; | ||
| import './utils.CO-iLyCr.js'; | ||
| import '#module-evaluator'; | ||
| import 'picomatch'; | ||
| import './coverage.BVb1JqW7.js'; | ||
| import './resolver.CERfsKE-.js'; | ||
| import 'es-module-lexer'; | ||
| import 'node:tty'; | ||
| import 'node:events'; | ||
| import './index.Chj8NDwU.js'; | ||
| import './modules.BJuCwlRJ.js'; | ||
| import 'node:child_process'; | ||
| import 'node:worker_threads'; | ||
| import 'readline'; | ||
| const jsxExample = { | ||
| name: "HelloWorld.jsx", | ||
| js: ` | ||
| export default function HelloWorld({ name }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| ts: ` | ||
| export default function HelloWorld({ name }: { name: string }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from '@testing-library/jsx' | ||
| import HelloWorld from './HelloWorld.<EXT>x' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(<HelloWorld name="Vitest" />) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const vueExample = { | ||
| name: "HelloWorld.vue", | ||
| js: ` | ||
| <script setup> | ||
| defineProps({ | ||
| name: String | ||
| }) | ||
| <\/script> | ||
| <template> | ||
| <div> | ||
| <h1>Hello {{ name }}!</h1> | ||
| </div> | ||
| </template> | ||
| `, | ||
| ts: ` | ||
| <script setup lang="ts"> | ||
| defineProps<{ | ||
| name: string | ||
| }>() | ||
| <\/script> | ||
| <template> | ||
| <div> | ||
| <h1>Hello {{ name }}!</h1> | ||
| </div> | ||
| </template> | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-vue' | ||
| import HelloWorld from './HelloWorld.vue' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(HelloWorld, { | ||
| props: { name: 'Vitest' }, | ||
| }) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const svelteExample = { | ||
| name: "HelloWorld.svelte", | ||
| js: ` | ||
| <script> | ||
| export let name | ||
| <\/script> | ||
| <h1>Hello {name}!</h1> | ||
| `, | ||
| ts: ` | ||
| <script lang="ts"> | ||
| export let name: string | ||
| <\/script> | ||
| <h1>Hello {name}!</h1> | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-svelte' | ||
| import HelloWorld from './HelloWorld.svelte' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(HelloWorld, { name: 'Vitest' }) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const markoExample = { | ||
| name: "HelloWorld.marko", | ||
| js: ` | ||
| class { | ||
| onCreate() { | ||
| this.state = { name: null } | ||
| } | ||
| } | ||
| <h1>Hello \${state.name}!</h1> | ||
| `, | ||
| ts: ` | ||
| export interface Input { | ||
| name: string | ||
| } | ||
| <h1>Hello \${input.name}!</h1> | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from '@marko/testing-library' | ||
| import HelloWorld from './HelloWorld.svelte' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(HelloWorld, { name: 'Vitest' }) | ||
| const element = getByText('Hello Vitest!') | ||
| expect(element).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const litExample = { | ||
| name: "HelloWorld.js", | ||
| js: ` | ||
| import { html, LitElement } from 'lit' | ||
| export class HelloWorld extends LitElement { | ||
| static properties = { | ||
| name: { type: String }, | ||
| } | ||
| constructor() { | ||
| super() | ||
| this.name = 'World' | ||
| } | ||
| render() { | ||
| return html\`<h1>Hello \${this.name}!</h1>\` | ||
| } | ||
| } | ||
| customElements.define('hello-world', HelloWorld) | ||
| `, | ||
| ts: ` | ||
| import { html, LitElement } from 'lit' | ||
| import { customElement, property } from 'lit/decorators.js' | ||
| @customElement('hello-world') | ||
| export class HelloWorld extends LitElement { | ||
| @property({ type: String }) | ||
| name = 'World' | ||
| render() { | ||
| return html\`<h1>Hello \${this.name}!</h1>\` | ||
| } | ||
| } | ||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| 'hello-world': HelloWorld | ||
| } | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-lit' | ||
| import { html } from 'lit' | ||
| import './HelloWorld.js' | ||
| test('renders name', async () => { | ||
| const screen = render(html\`<hello-world name="Vitest"></hello-world>\`) | ||
| const element = screen.getByText('Hello Vitest!') | ||
| await expect.element(element).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const qwikExample = { | ||
| name: "HelloWorld.jsx", | ||
| js: ` | ||
| import { component$ } from '@builder.io/qwik' | ||
| export default component$(({ name }) => { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| }) | ||
| `, | ||
| ts: ` | ||
| import { component$ } from '@builder.io/qwik' | ||
| export default component$(({ name }: { name: string }) => { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| }) | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-qwik' | ||
| import HelloWorld from './HelloWorld.tsx' | ||
| test('renders name', async () => { | ||
| const { getByText } = render(<HelloWorld name="Vitest" />) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const preactExample = { | ||
| name: "HelloWorld.jsx", | ||
| js: ` | ||
| export default function HelloWorld({ name }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| ts: ` | ||
| export default function HelloWorld({ name }: { name: string }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-preact' | ||
| import HelloWorld from './HelloWorld.<EXT>x' | ||
| test('renders name', async () => { | ||
| const { getByText } = render(<HelloWorld name="Vitest" />) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const vanillaExample = { | ||
| name: "HelloWorld.js", | ||
| js: ` | ||
| export default function HelloWorld({ name }) { | ||
| const parent = document.createElement('div') | ||
| const h1 = document.createElement('h1') | ||
| h1.textContent = 'Hello ' + name + '!' | ||
| parent.appendChild(h1) | ||
| return parent | ||
| } | ||
| `, | ||
| ts: ` | ||
| export default function HelloWorld({ name }: { name: string }): HTMLDivElement { | ||
| const parent = document.createElement('div') | ||
| const h1 = document.createElement('h1') | ||
| h1.textContent = 'Hello ' + name + '!' | ||
| parent.appendChild(h1) | ||
| return parent | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { getByText } from '@testing-library/dom' | ||
| import HelloWorld from './HelloWorld.js' | ||
| test('renders name', () => { | ||
| const parent = HelloWorld({ name: 'Vitest' }) | ||
| document.body.appendChild(parent) | ||
| const element = getByText(parent, 'Hello Vitest!') | ||
| expect(element).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| function getExampleTest(framework) { | ||
| switch (framework) { | ||
| case "solid": return { | ||
| ...jsxExample, | ||
| test: jsxExample.test.replace("@testing-library/jsx", `@testing-library/${framework}`) | ||
| }; | ||
| case "preact": return preactExample; | ||
| case "react": return { | ||
| ...jsxExample, | ||
| test: jsxExample.test.replace("@testing-library/jsx", `vitest-browser-${framework}`) | ||
| }; | ||
| case "vue": return vueExample; | ||
| case "svelte": return svelteExample; | ||
| case "lit": return litExample; | ||
| case "marko": return markoExample; | ||
| case "qwik": return qwikExample; | ||
| default: return vanillaExample; | ||
| } | ||
| } | ||
| async function generateExampleFiles(framework, lang) { | ||
| const example = getExampleTest(framework); | ||
| let fileName = example.name; | ||
| const folder = resolve(process.cwd(), "vitest-example"); | ||
| const fileContent = example[lang]; | ||
| if (!existsSync(folder)) await mkdir(folder, { recursive: true }); | ||
| const isJSX = fileName.endsWith(".jsx"); | ||
| if (isJSX && lang === "ts") fileName = fileName.replace(".jsx", ".tsx"); | ||
| else if (fileName.endsWith(".js") && lang === "ts") fileName = fileName.replace(".js", ".ts"); | ||
| example.test = example.test.replace("<EXT>", lang); | ||
| const filePath = resolve(folder, fileName); | ||
| const testPath = resolve(folder, `HelloWorld.test.${isJSX ? `${lang}x` : lang}`); | ||
| writeFileSync(filePath, fileContent.trimStart(), "utf-8"); | ||
| writeFileSync(testPath, example.test.trimStart(), "utf-8"); | ||
| return testPath; | ||
| } | ||
| // eslint-disable-next-line no-console | ||
| const log = console.log; | ||
| function getProviderOptions() { | ||
| return Object.entries({ | ||
| playwright: "Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev", | ||
| webdriverio: "WebdriverIO uses WebDriver protocol. Read more: https://webdriver.io", | ||
| preview: "Preview is useful to quickly run your tests in the browser, but not suitable for CI." | ||
| }).map(([provider, description]) => { | ||
| return { | ||
| title: provider, | ||
| description, | ||
| value: provider | ||
| }; | ||
| }); | ||
| } | ||
| function getBrowserNames(provider) { | ||
| switch (provider) { | ||
| case "webdriverio": return [ | ||
| "chrome", | ||
| "firefox", | ||
| "edge", | ||
| "safari" | ||
| ]; | ||
| case "playwright": return [ | ||
| "chromium", | ||
| "firefox", | ||
| "webkit" | ||
| ]; | ||
| case "preview": return [ | ||
| "chrome", | ||
| "firefox", | ||
| "safari" | ||
| ]; | ||
| } | ||
| } | ||
| function getFramework() { | ||
| return [ | ||
| { | ||
| title: "vanilla", | ||
| value: "vanilla", | ||
| description: "No framework, just plain JavaScript or TypeScript." | ||
| }, | ||
| { | ||
| title: "vue", | ||
| value: "vue", | ||
| description: "\"The Progressive JavaScript Framework\"" | ||
| }, | ||
| { | ||
| title: "svelte", | ||
| value: "svelte", | ||
| description: "\"Svelte: cybernetically enhanced web apps\"" | ||
| }, | ||
| { | ||
| title: "react", | ||
| value: "react", | ||
| description: "\"The library for web and native user interfaces\"" | ||
| }, | ||
| { | ||
| title: "lit", | ||
| value: "lit", | ||
| description: "\"A simple library for building fast, lightweight web components.\"" | ||
| }, | ||
| { | ||
| title: "preact", | ||
| value: "preact", | ||
| description: "\"Fast 3kB alternative to React with the same modern API\"" | ||
| }, | ||
| { | ||
| title: "solid", | ||
| value: "solid", | ||
| description: "\"Simple and performant reactivity for building user interfaces\"" | ||
| }, | ||
| { | ||
| title: "marko", | ||
| value: "marko", | ||
| description: "\"A declarative, HTML-based language that makes building web apps fun\"" | ||
| }, | ||
| { | ||
| title: "qwik", | ||
| value: "qwik", | ||
| description: "\"Instantly interactive web apps at scale\"" | ||
| } | ||
| ]; | ||
| } | ||
| function getFrameworkTestPackage(framework) { | ||
| switch (framework) { | ||
| case "vanilla": return null; | ||
| case "vue": return "vitest-browser-vue"; | ||
| case "svelte": return "vitest-browser-svelte"; | ||
| case "react": return "vitest-browser-react"; | ||
| case "lit": return "vitest-browser-lit"; | ||
| case "preact": return "vitest-browser-preact"; | ||
| case "solid": return "@solidjs/testing-library"; | ||
| case "marko": return "@marko/testing-library"; | ||
| case "qwik": return "vitest-browser-qwik"; | ||
| } | ||
| throw new Error(`Unsupported framework: ${framework}`); | ||
| } | ||
| function getFrameworkPluginPackage(framework) { | ||
| switch (framework) { | ||
| case "vue": return "@vitejs/plugin-vue"; | ||
| case "svelte": return "@sveltejs/vite-plugin-svelte"; | ||
| case "react": return "@vitejs/plugin-react"; | ||
| case "preact": return "@preact/preset-vite"; | ||
| case "solid": return "vite-plugin-solid"; | ||
| case "marko": return "@marko/vite"; | ||
| case "qwik": return "@builder.io/qwik/optimizer"; | ||
| } | ||
| return null; | ||
| } | ||
| function getLanguageOptions() { | ||
| return [{ | ||
| title: "TypeScript", | ||
| description: "Use TypeScript.", | ||
| value: "ts" | ||
| }, { | ||
| title: "JavaScript", | ||
| description: "Use plain JavaScript.", | ||
| value: "js" | ||
| }]; | ||
| } | ||
| async function installPackages(pkgManager, packages) { | ||
| if (!packages.length) { | ||
| log(y.green("✔"), y.bold("All packages are already installed.")); | ||
| return; | ||
| } | ||
| log(y.cyan("◼"), y.bold("Installing packages...")); | ||
| log(y.cyan("◼"), packages.join(", ")); | ||
| log(); | ||
| await installPackage(packages, { | ||
| dev: true, | ||
| packageManager: pkgManager ?? void 0 | ||
| }); | ||
| } | ||
| function readPkgJson(path) { | ||
| if (!existsSync(path)) return null; | ||
| const content = readFileSync(path, "utf-8"); | ||
| return JSON.parse(content); | ||
| } | ||
| function getPossibleDefaults(dependencies) { | ||
| return { | ||
| lang: "ts", | ||
| provider: getPossibleProvider(dependencies), | ||
| framework: getPossibleFramework(dependencies) | ||
| }; | ||
| } | ||
| function getPossibleFramework(dependencies) { | ||
| if (dependencies.vue || dependencies["vue-tsc"] || dependencies["@vue/reactivity"]) return "vue"; | ||
| if (dependencies.react || dependencies["react-dom"]) return "react"; | ||
| if (dependencies.svelte || dependencies["@sveltejs/kit"]) return "svelte"; | ||
| if (dependencies.lit || dependencies["lit-html"]) return "lit"; | ||
| if (dependencies.preact) return "preact"; | ||
| if (dependencies["solid-js"] || dependencies["@solidjs/start"]) return "solid"; | ||
| if (dependencies.marko) return "marko"; | ||
| if (dependencies["@builder.io/qwik"] || dependencies["@qwik.dev/core"]) return "qwik"; | ||
| return "vanilla"; | ||
| } | ||
| function getPossibleProvider(dependencies) { | ||
| if (dependencies.webdriverio || dependencies["@wdio/cli"] || dependencies["@wdio/config"]) return "webdriverio"; | ||
| // playwright is the default recommendation | ||
| return "playwright"; | ||
| } | ||
| function getProviderDocsLink(provider) { | ||
| switch (provider) { | ||
| case "playwright": return "https://vitest.dev/config/browser/playwright"; | ||
| case "webdriverio": return "https://vitest.dev/config/browser/webdriverio"; | ||
| } | ||
| } | ||
| function sort(choices, value) { | ||
| const index = choices.findIndex((i) => i.value === value); | ||
| if (index === -1) return choices; | ||
| return [choices.splice(index, 1)[0], ...choices]; | ||
| } | ||
| function fail() { | ||
| process.exitCode = 1; | ||
| } | ||
| function getFrameworkImportInfo(framework) { | ||
| switch (framework) { | ||
| case "svelte": return { | ||
| importName: "svelte", | ||
| isNamedExport: true | ||
| }; | ||
| case "qwik": return { | ||
| importName: "qwikVite", | ||
| isNamedExport: true | ||
| }; | ||
| default: return { | ||
| importName: framework, | ||
| isNamedExport: false | ||
| }; | ||
| } | ||
| } | ||
| async function generateFrameworkConfigFile(options) { | ||
| const { importName, isNamedExport } = getFrameworkImportInfo(options.framework); | ||
| const frameworkImport = isNamedExport ? `import { ${importName} } from '${options.frameworkPlugin}'` : `import ${importName} from '${options.frameworkPlugin}'`; | ||
| const configContent = [ | ||
| `import { defineConfig } from 'vitest/config'`, | ||
| `import { ${options.provider} } from '@vitest/browser-${options.provider}'`, | ||
| options.frameworkPlugin ? frameworkImport : null, | ||
| ``, | ||
| "export default defineConfig({", | ||
| options.frameworkPlugin ? ` plugins: [${importName}()],` : null, | ||
| ` test: {`, | ||
| ` browser: {`, | ||
| ` enabled: true,`, | ||
| ` provider: ${options.provider}(),`, | ||
| options.provider !== "preview" && ` // ${getProviderDocsLink(options.provider)}`, | ||
| ` instances: [`, | ||
| ...options.browsers.map((browser) => ` { browser: '${browser}' },`), | ||
| ` ],`, | ||
| ` },`, | ||
| ` },`, | ||
| `})`, | ||
| "" | ||
| ].filter((t) => typeof t === "string").join("\n"); | ||
| await writeFile(options.configPath, configContent); | ||
| } | ||
| async function updatePkgJsonScripts(pkgJsonPath, vitestScript) { | ||
| if (!existsSync(pkgJsonPath)) { | ||
| const pkg = { scripts: { "test:browser": vitestScript } }; | ||
| await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8"); | ||
| } else { | ||
| const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8")); | ||
| pkg.scripts = pkg.scripts || {}; | ||
| pkg.scripts["test:browser"] = vitestScript; | ||
| await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8"); | ||
| } | ||
| log(y.green("✔"), "Added \"test:browser\" script to your package.json."); | ||
| } | ||
| function getRunScript(pkgManager) { | ||
| switch (pkgManager) { | ||
| case "yarn@berry": | ||
| case "yarn": return "yarn test:browser"; | ||
| case "pnpm@6": | ||
| case "pnpm": return "pnpm test:browser"; | ||
| case "bun": return "bun test:browser"; | ||
| default: return "npm run test:browser"; | ||
| } | ||
| } | ||
| function getPlaywrightRunArgs(pkgManager) { | ||
| switch (pkgManager) { | ||
| case "yarn@berry": | ||
| case "yarn": return ["yarn", "exec"]; | ||
| case "pnpm@6": | ||
| case "pnpm": return ["pnpx"]; | ||
| case "bun": return ["bunx"]; | ||
| default: return ["npx"]; | ||
| } | ||
| } | ||
| async function create() { | ||
| log(y.cyan("◼"), "This utility will help you set up a browser testing environment.\n"); | ||
| const pkgJsonPath = resolve(process.cwd(), "package.json"); | ||
| const pkg = readPkgJson(pkgJsonPath) || {}; | ||
| const dependencies = { | ||
| ...pkg.dependencies, | ||
| ...pkg.devDependencies | ||
| }; | ||
| const defaults = getPossibleDefaults(dependencies); | ||
| const { lang } = await prompt({ | ||
| type: "select", | ||
| name: "lang", | ||
| message: "Choose a language for your tests", | ||
| choices: sort(getLanguageOptions(), defaults?.lang) | ||
| }); | ||
| if (!lang) return fail(); | ||
| const { provider } = await prompt({ | ||
| type: "select", | ||
| name: "provider", | ||
| message: "Choose a browser provider. Vitest will use its API to control the testing environment", | ||
| choices: sort(getProviderOptions(), defaults?.provider) | ||
| }); | ||
| if (!provider) return fail(); | ||
| const { browsers } = await prompt({ | ||
| type: "multiselect", | ||
| name: "browsers", | ||
| message: "Choose a browser", | ||
| choices: getBrowserNames(provider).map((browser) => ({ | ||
| title: browser, | ||
| value: browser | ||
| })) | ||
| }); | ||
| if (!provider) return fail(); | ||
| const { framework } = await prompt({ | ||
| type: "select", | ||
| name: "framework", | ||
| message: "Choose your framework", | ||
| choices: sort(getFramework(), defaults?.framework) | ||
| }); | ||
| if (!framework) return fail(); | ||
| let installPlaywright = false; | ||
| if (provider === "playwright") ({installPlaywright} = await prompt({ | ||
| type: "confirm", | ||
| name: "installPlaywright", | ||
| message: `Install Playwright browsers (can be done manually via 'pnpm exec playwright install')?` | ||
| })); | ||
| if (installPlaywright == null) return fail(); | ||
| const dependenciesToInstall = [`@vitest/browser-${provider}`]; | ||
| const frameworkPackage = getFrameworkTestPackage(framework); | ||
| if (frameworkPackage) dependenciesToInstall.push(frameworkPackage); | ||
| const frameworkPlugin = getFrameworkPluginPackage(framework); | ||
| if (frameworkPlugin) dependenciesToInstall.push(frameworkPlugin); | ||
| const pkgManager = await detectPackageManager(); | ||
| log(); | ||
| await installPackages(pkgManager, dependenciesToInstall.filter((pkg) => !dependencies[pkg])); | ||
| const rootConfig = findConfigFile(process.cwd()); | ||
| let scriptCommand = "vitest"; | ||
| log(); | ||
| if (rootConfig) { | ||
| const configPath = resolve(dirname(rootConfig), `vitest.browser.config.${lang}`); | ||
| scriptCommand = `vitest --config=${relative(process.cwd(), configPath)}`; | ||
| await generateFrameworkConfigFile({ | ||
| configPath, | ||
| framework, | ||
| frameworkPlugin, | ||
| provider, | ||
| browsers | ||
| }); | ||
| log( | ||
| y.green("✔"), | ||
| "Created a new config file for browser tests:", | ||
| y.bold(relative(process.cwd(), configPath)), | ||
| // TODO: Can we modify the config ourselves? | ||
| "\nSince you already have a Vitest config file, it is recommended to copy the contents of the new file ", | ||
| "into your existing config located at ", | ||
| y.bold(relative(process.cwd(), rootConfig)) | ||
| ); | ||
| } else { | ||
| const configPath = resolve(process.cwd(), `vitest.config.${lang}`); | ||
| await generateFrameworkConfigFile({ | ||
| configPath, | ||
| framework, | ||
| frameworkPlugin, | ||
| provider, | ||
| browsers | ||
| }); | ||
| log(y.green("✔"), "Created a config file for browser tests:", y.bold(relative(process.cwd(), configPath))); | ||
| } | ||
| log(); | ||
| await updatePkgJsonScripts(pkgJsonPath, scriptCommand); | ||
| if (installPlaywright) { | ||
| log(); | ||
| const [command, ...args] = getPlaywrightRunArgs(pkgManager); | ||
| const allArgs = [ | ||
| ...args, | ||
| "playwright", | ||
| "install", | ||
| "--with-deps" | ||
| ]; | ||
| log(y.cyan("◼"), `Installing Playwright dependencies with \`${y.bold(command)} ${y.bold(allArgs.join(" "))}\`...`); | ||
| log(); | ||
| await x(command, allArgs, { nodeOptions: { stdio: [ | ||
| "pipe", | ||
| "inherit", | ||
| "inherit" | ||
| ] } }); | ||
| } | ||
| log(); | ||
| const exampleTestFile = await generateExampleFiles(framework, lang); | ||
| log(y.green("✔"), "Created example test file in", y.bold(relative(process.cwd(), exampleTestFile))); | ||
| log(y.dim(" You can safely delete this file once you have written your own tests.")); | ||
| log(); | ||
| log(y.cyan("◼"), "All done! Run your tests with", y.bold(getRunScript(pkgManager))); | ||
| } | ||
| export { create }; |
| import nodeos__default from 'node:os'; | ||
| import './env.DzFJjrmK.js'; | ||
| import { isCI, isAgent } from 'std-env'; | ||
| const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"]; | ||
| const defaultExclude = ["**/node_modules/**", "**/.git/**"]; | ||
| const benchmarkConfigDefaults = { | ||
| enabled: false, | ||
| include: ["**/*.{bench,benchmark}.?(c|m)[jt]s?(x)"], | ||
| exclude: defaultExclude, | ||
| includeSource: [], | ||
| retainSamples: false, | ||
| suppressExportGetterWarnings: false, | ||
| projectName: "" | ||
| }; | ||
| // These are the generic defaults for coverage. Providers may also set some provider specific defaults. | ||
| const coverageConfigDefaults = { | ||
| provider: "v8", | ||
| enabled: false, | ||
| clean: true, | ||
| cleanOnRerun: true, | ||
| reportsDirectory: "./coverage", | ||
| exclude: [], | ||
| reportOnFailure: false, | ||
| reporter: [ | ||
| "text", | ||
| "html", | ||
| "clover", | ||
| "json" | ||
| ], | ||
| allowExternal: false, | ||
| excludeAfterRemap: false, | ||
| processingConcurrency: Math.min(20, nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length), | ||
| ignoreClassMethods: [], | ||
| skipFull: false, | ||
| watermarks: { | ||
| statements: [50, 80], | ||
| functions: [50, 80], | ||
| branches: [50, 80], | ||
| lines: [50, 80] | ||
| }, | ||
| autoAttachSubprocess: false | ||
| }; | ||
| const fakeTimersDefaults = { | ||
| loopLimit: 1e4, | ||
| shouldClearNativeTimers: true | ||
| }; | ||
| const configDefaults = Object.freeze({ | ||
| allowOnly: !isCI, | ||
| isolate: true, | ||
| watch: !isCI && process.stdin.isTTY && !isAgent, | ||
| globals: false, | ||
| injectCjsGlobals: true, | ||
| environment: "node", | ||
| clearMocks: true, | ||
| restoreMocks: false, | ||
| mockReset: false, | ||
| unstubGlobals: false, | ||
| unstubEnvs: false, | ||
| include: defaultInclude, | ||
| exclude: defaultExclude, | ||
| teardownTimeout: 1e4, | ||
| forceRerunTriggers: ["**/package.json", "**/{vitest,vite}.config.*"], | ||
| update: false, | ||
| reporters: [isAgent ? "minimal" : "default", ...process.env.GITHUB_ACTIONS === "true" ? ["github-actions"] : []], | ||
| silent: false, | ||
| hideSkippedTests: false, | ||
| api: false, | ||
| ui: false, | ||
| uiBase: "/__vitest__/", | ||
| open: !isCI, | ||
| css: { include: [] }, | ||
| coverage: coverageConfigDefaults, | ||
| fakeTimers: fakeTimersDefaults, | ||
| maxConcurrency: 5, | ||
| dangerouslyIgnoreUnhandledErrors: false, | ||
| typecheck: { | ||
| checker: "tsc", | ||
| include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"], | ||
| exclude: defaultExclude | ||
| }, | ||
| slowTestThreshold: 300, | ||
| taskTitleValueFormatTruncate: 40, | ||
| disableConsoleIntercept: false, | ||
| detectAsyncLeaks: false | ||
| }); | ||
| export { coverageConfigDefaults as a, defaultInclude as b, configDefaults as c, defaultExclude as d, benchmarkConfigDefaults as e }; |
| import { f as format$1, p as plugins, c as createDOMElementFilter } from './index.DzTmMrSM.js'; | ||
| const { AsymmetricMatcher, DOMCollection, DOMElement, Immutable, ReactElement, ReactTestComponent } = plugins; | ||
| const PLUGINS = [ | ||
| ReactTestComponent, | ||
| ReactElement, | ||
| DOMElement, | ||
| DOMCollection, | ||
| Immutable, | ||
| AsymmetricMatcher | ||
| ]; | ||
| function stringify(object, maxDepth = 10, { maxLength, filterNode, ...options } = {}) { | ||
| const MAX_LENGTH = maxLength ?? 1e4; | ||
| let result; | ||
| // Convert string selector to filter function | ||
| const filterFn = typeof filterNode === "string" ? createNodeFilterFromSelector(filterNode) : filterNode; | ||
| const plugins = filterFn ? [ | ||
| ReactTestComponent, | ||
| ReactElement, | ||
| createDOMElementFilter(filterFn), | ||
| DOMCollection, | ||
| Immutable, | ||
| AsymmetricMatcher | ||
| ] : PLUGINS; | ||
| try { | ||
| result = format$1(object, { | ||
| maxDepth, | ||
| escapeString: false, | ||
| plugins, | ||
| ...options | ||
| }); | ||
| } catch { | ||
| result = format$1(object, { | ||
| callToJSON: false, | ||
| maxDepth, | ||
| escapeString: false, | ||
| plugins, | ||
| ...options | ||
| }); | ||
| } | ||
| // Prevents infinite loop https://github.com/vitest-dev/vitest/issues/7249 | ||
| return result.length >= MAX_LENGTH && maxDepth > 1 ? stringify(object, Math.floor(Math.min(maxDepth, Number.MAX_SAFE_INTEGER) / 2), { | ||
| maxLength, | ||
| filterNode, | ||
| ...options | ||
| }) : result; | ||
| } | ||
| function createNodeFilterFromSelector(selector) { | ||
| const ELEMENT_NODE = 1; | ||
| const COMMENT_NODE = 8; | ||
| return (node) => { | ||
| // Filter out comments | ||
| if (node.nodeType === COMMENT_NODE) return false; | ||
| // Filter out elements matching the selector | ||
| if (node.nodeType === ELEMENT_NODE && node.matches) try { | ||
| return !node.matches(selector); | ||
| } catch { | ||
| return true; | ||
| } | ||
| return true; | ||
| }; | ||
| } | ||
| const formatRegExp = /%[sdjifoOc%]/g; | ||
| function format(args, options = {}) { | ||
| const formatArg = (item) => inspect(item, options); | ||
| if (typeof args[0] !== "string") { | ||
| const objects = []; | ||
| for (let i = 0; i < args.length; i++) objects.push(formatArg(args[i])); | ||
| return objects.join(" "); | ||
| } | ||
| const len = args.length; | ||
| let i = 1; | ||
| const template = args[0]; | ||
| let str = String(template).replace(formatRegExp, (x) => { | ||
| if (x === "%%") return "%"; | ||
| if (i >= len) return x; | ||
| switch (x) { | ||
| case "%s": { | ||
| const value = args[i++]; | ||
| if (typeof value === "bigint") return `${value.toString()}n`; | ||
| if (typeof value === "number" && value === 0 && 1 / value < 0) return "-0"; | ||
| if (typeof value === "object" && value !== null) { | ||
| if (typeof value.toString === "function" && value.toString !== Object.prototype.toString) return value.toString(); | ||
| return formatArg(value); | ||
| } | ||
| return String(value); | ||
| } | ||
| case "%d": { | ||
| const value = args[i++]; | ||
| if (typeof value === "bigint") return `${value.toString()}n`; | ||
| if (typeof value === "symbol") return "NaN"; | ||
| return Number(value).toString(); | ||
| } | ||
| case "%i": { | ||
| const value = args[i++]; | ||
| if (typeof value === "bigint") return `${value.toString()}n`; | ||
| return Number.parseInt(String(value)).toString(); | ||
| } | ||
| case "%f": return Number.parseFloat(String(args[i++])).toString(); | ||
| case "%o": | ||
| case "%O": return formatArg(args[i++]); | ||
| case "%c": | ||
| i++; | ||
| return ""; | ||
| case "%j": try { | ||
| return JSON.stringify(args[i++]); | ||
| } catch (err) { | ||
| const m = err.message; | ||
| if (m.includes("circular structure") || m.includes("cyclic structures") || m.includes("cyclic object")) return "[Circular]"; | ||
| throw err; | ||
| } | ||
| default: return x; | ||
| } | ||
| }); | ||
| for (let x = args[i]; i < len; x = args[++i]) if (x === null || typeof x !== "object") str += ` ${typeof x === "symbol" ? x.toString() : x}`; | ||
| else str += ` ${formatArg(x)}`; | ||
| return str; | ||
| } | ||
| function inspect(obj, options) { | ||
| const { truncate, multiline, ...stringifyOptions } = options ?? {}; | ||
| const prettyFormatOptions = { | ||
| singleQuote: true, | ||
| quoteKeys: false, | ||
| min: true, | ||
| spacingInner: " ", | ||
| spacingOuter: " ", | ||
| printBasicPrototype: false, | ||
| compareKeys: null, | ||
| ...multiline ? { | ||
| min: false, | ||
| spacingInner: void 0, | ||
| spacingOuter: void 0 | ||
| } : {} | ||
| }; | ||
| const threshold = truncate ?? 0; | ||
| const formatted = stringify(obj, void 0, { | ||
| ...prettyFormatOptions, | ||
| ...stringifyOptions, | ||
| maxLength: threshold || void 0 | ||
| }); | ||
| if (threshold === 0 || formatted.length <= threshold) return formatted; | ||
| // if stringify's adaptive maxDepth (down to 1) fails to truncate enough, | ||
| // - for known types (e.g. string, object, array, etc), apply best effort truncation. | ||
| // - for other values, fallback to maxDepth = 0 which should can show minimal output. | ||
| const type = Object.prototype.toString.call(obj); | ||
| if (typeof obj === "string") { | ||
| let end = threshold - 1; | ||
| if (end > 0 && isHighSurrogate(formatted[end - 1])) end = end - 1; | ||
| return `'${formatted.slice(1, end)}…'`; | ||
| } | ||
| if (type === "[object Array]" || type === "[object Object]" || type === "[object Set]" || type === "[object Map]") return stringifyByMaxWidth(obj, threshold, { | ||
| ...prettyFormatOptions, | ||
| ...stringifyOptions, | ||
| maxDepth: 1 | ||
| }); | ||
| return stringify(obj, void 0, { | ||
| ...prettyFormatOptions, | ||
| ...stringifyOptions, | ||
| maxDepth: 0 | ||
| }); | ||
| } | ||
| function truncateString(string, maxLength) { | ||
| if (string.length <= maxLength) return string; | ||
| let end = maxLength - 1; | ||
| if (isHighSurrogate(string[end - 1])) end = end - 1; | ||
| return `${string.slice(0, end)}…`; | ||
| } | ||
| function stringifyByMaxWidth(object, threshold, options) { | ||
| function evaluate(x) { | ||
| return stringify(object, void 0, { | ||
| ...options, | ||
| maxWidth: x | ||
| }); | ||
| } | ||
| return evaluate(binarySearch(0, threshold, (x) => evaluate(x).length <= threshold)); | ||
| } | ||
| // find max(x \in [x, y) | f(x) = true) | ||
| // if f(x0) is false, then returns x0. | ||
| function binarySearch(x0, x1, f) { | ||
| while (x0 + 1 < x1) { | ||
| const x = Math.floor((x0 + x1) / 2); | ||
| if (f(x)) x0 = x; | ||
| else x1 = x; | ||
| } | ||
| return x0; | ||
| } | ||
| // https://github.com/chaijs/loupe/pull/79 | ||
| function isHighSurrogate(char) { | ||
| return char >= "\ud800" && char <= "\udbff"; | ||
| } | ||
| export { formatRegExp as a, format as f, inspect as i, stringify as s, truncateString as t }; |
| import { isCI } from 'std-env'; | ||
| const isNode = typeof process < "u" && typeof process.stdout < "u" && !process.versions?.deno && !globalThis.window; | ||
| const isDeno = typeof process < "u" && typeof process.stdout < "u" && process.versions?.deno !== void 0; | ||
| const isWindows = (isNode || isDeno) && process.platform === "win32"; | ||
| const isTTY = (isNode || isDeno) && process.stdout?.isTTY && !isCI; | ||
| const isForceColor = () => "FORCE_COLOR" in process.env; | ||
| export { isForceColor as a, isTTY as b, isWindows as i }; |
| import { A as Awaitable } from './config.d.DsC1jkby.js'; | ||
| interface EnvironmentReturn { | ||
| teardown: (global: any) => Awaitable<void>; | ||
| } | ||
| interface VmEnvironmentReturn { | ||
| getVmContext: () => { | ||
| [key: string]: any; | ||
| }; | ||
| teardown: () => Awaitable<void>; | ||
| } | ||
| interface Environment { | ||
| name: string; | ||
| /** | ||
| * @deprecated use `viteEnvironment` instead. Uses `name` by default | ||
| */ | ||
| transformMode?: "web" | "ssr"; | ||
| /** | ||
| * Environment initiated by the Vite server. It is usually available | ||
| * as `vite.server.environments.${name}`. | ||
| * | ||
| * By default, fallbacks to `name`. | ||
| */ | ||
| viteEnvironment?: "client" | "ssr" | ({} & string); | ||
| setupVM?: (options: Record<string, any>) => Awaitable<VmEnvironmentReturn>; | ||
| setup: (global: any, options: Record<string, any>) => Awaitable<EnvironmentReturn>; | ||
| } | ||
| export type { Environment as E, VmEnvironmentReturn as V, EnvironmentReturn as a }; |
| import { g as globalApis } from './constants.-juJ8b_4.js'; | ||
| import { i as index } from './index.CLtI1k_4.js'; | ||
| import './artifact.DC5WoEgy.js'; | ||
| import './index.DzTmMrSM.js'; | ||
| import './tinyrainbow.Ht9iggcq.js'; | ||
| import './display.CYwyMF4S.js'; | ||
| import './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import './source-map.DZdIqpIJ.js'; | ||
| import '../task-utils.js'; | ||
| import './utils.DYj33du9.js'; | ||
| import './spy.B8mHA9qu.js'; | ||
| import './rpc.iNjF664v.js'; | ||
| import 'vite/module-runner'; | ||
| import './index.Chj8NDwU.js'; | ||
| import 'chai'; | ||
| import './plugins.CsoX-42X.js'; | ||
| import './offset.Dy-5Fdfn.js'; | ||
| import 'tinybench'; | ||
| import 'expect-type'; | ||
| function registerApiGlobally() { | ||
| globalApis.forEach((api) => { | ||
| // @ts-expect-error I know what I am doing :P | ||
| globalThis[api] = index[api]; | ||
| }); | ||
| } | ||
| export { registerApiGlobally }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| import fs__default from 'node:fs'; | ||
| import { n as normalize, k as splitFileAndPostfix$1, j as join, l as isBareImport } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { E as EnvironmentTeardownError, a as getSafeWorkerState } from './utils.DYj33du9.js'; | ||
| import { pathToFileURL, URL as URL$1 } from 'node:url'; | ||
| import { distDir } from '../path.js'; | ||
| import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js'; | ||
| import { isAbsolute, resolve } from 'node:path'; | ||
| import vm from 'node:vm'; | ||
| import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker'; | ||
| import { findMockRedirect } from '@vitest/mocker/redirect'; | ||
| import * as viteModuleRunner from 'vite/module-runner'; | ||
| import { Traces } from '../traces.js'; | ||
| import { Console } from 'node:console'; | ||
| class BareModuleMocker { | ||
| static pendingIds = []; | ||
| spyModule; | ||
| primitives; | ||
| registries = /* @__PURE__ */ new Map(); | ||
| mockContext = { callstack: null }; | ||
| _otel; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this._otel = options.traces; | ||
| this.primitives = { | ||
| Object, | ||
| Error, | ||
| Function, | ||
| RegExp, | ||
| Symbol: globalThis.Symbol, | ||
| Array, | ||
| Map | ||
| }; | ||
| if (options.spyModule) this.spyModule = options.spyModule; | ||
| } | ||
| get root() { | ||
| return this.options.root; | ||
| } | ||
| get moduleDirectories() { | ||
| return this.options.moduleDirectories || []; | ||
| } | ||
| getMockerRegistry() { | ||
| const suite = this.getSuiteFilepath(); | ||
| if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry()); | ||
| return this.registries.get(suite); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(_id) { | ||
| // implemented by mockers that control the module runner | ||
| } | ||
| isModuleDirectory(path) { | ||
| return this.moduleDirectories.some((dir) => path.includes(dir)); | ||
| } | ||
| getSuiteFilepath() { | ||
| return this.options.getCurrentTestFilepath() || "global"; | ||
| } | ||
| createError(message, codeFrame) { | ||
| const Error = this.primitives.Error; | ||
| const error = new Error(message); | ||
| Object.assign(error, { codeFrame }); | ||
| return error; | ||
| } | ||
| async resolveId(rawId, importer) { | ||
| return this._otel.$("vitest.mocker.resolve_id", { attributes: { | ||
| "vitest.module.raw_id": rawId, | ||
| "vitest.module.importer": rawId | ||
| } }, async (span) => { | ||
| const result = await this.options.resolveId(rawId, importer); | ||
| if (!result) { | ||
| span.addEvent("could not resolve id, fallback to unresolved values"); | ||
| const id = normalizeModuleId(rawId); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": rawId, | ||
| "vitest.module.external": id, | ||
| "vitest.module.fallback": true | ||
| }); | ||
| return { | ||
| id, | ||
| url: rawId, | ||
| external: id | ||
| }; | ||
| } | ||
| // external is node_module or unresolved module | ||
| // for example, some people mock "vscode" and don't have it installed | ||
| const external = !isAbsolute(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null; | ||
| const id = normalizeModuleId(result.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.external": external ?? false | ||
| }); | ||
| return { | ||
| ...result, | ||
| id, | ||
| external | ||
| }; | ||
| }); | ||
| } | ||
| async resolveMocks() { | ||
| if (!BareModuleMocker.pendingIds.length) return; | ||
| const resolveMock = async (mock) => { | ||
| const { id, url, external } = await this.resolveId(mock.id, mock.importer); | ||
| if (mock.action === "unmock") this.unmockPath(id); | ||
| if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory); | ||
| }; | ||
| // group consecutive mocks of the same action type together, | ||
| // resolve in parallel inside each group, but run groups sequentially | ||
| // to preserve mock/unmock ordering | ||
| const groups = groupByConsecutiveAction(BareModuleMocker.pendingIds); | ||
| for (const group of groups) await Promise.all(group.map(resolveMock)); | ||
| BareModuleMocker.pendingIds = []; | ||
| } | ||
| // public method to avoid circular dependency | ||
| getMockContext() { | ||
| return this.mockContext; | ||
| } | ||
| // path used to store mocked dependencies | ||
| getMockPath(dep) { | ||
| return `mock:${dep}`; | ||
| } | ||
| getDependencyMock(id) { | ||
| return this.getMockerRegistry().getById(fixLeadingSlashes(id)); | ||
| } | ||
| getDependencyMockByUrl(url) { | ||
| return this.getMockerRegistry().get(url); | ||
| } | ||
| findMockRedirect(mockPath, external) { | ||
| return findMockRedirect(this.root, mockPath, external); | ||
| } | ||
| mockObject(object, mockExportsOrModuleType, moduleType) { | ||
| let mockExports; | ||
| if (mockExportsOrModuleType === "automock" || mockExportsOrModuleType === "autospy") { | ||
| moduleType = mockExportsOrModuleType; | ||
| mockExports = void 0; | ||
| } else mockExports = mockExportsOrModuleType; | ||
| moduleType ??= "automock"; | ||
| const createMockInstance = this.spyModule?.createMockInstance; | ||
| if (!createMockInstance) throw this.createError("[vitest] `spyModule` is not defined. This is a Vitest error. Please open a new issue with reproduction."); | ||
| return mockObject({ | ||
| globalConstructors: this.primitives, | ||
| createMockInstance, | ||
| type: moduleType | ||
| }, object, mockExports); | ||
| } | ||
| unmockPath(id) { | ||
| this.getMockerRegistry().deleteById(id); | ||
| this.invalidateModuleById(id); | ||
| } | ||
| mockPath(originalId, id, url, external, mockType, factory) { | ||
| const registry = this.getMockerRegistry(); | ||
| if (mockType === "manual") registry.register("manual", originalId, id, url, factory); | ||
| else if (mockType === "autospy") registry.register("autospy", originalId, id, url); | ||
| else { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) registry.register("redirect", originalId, id, url, redirect); | ||
| else registry.register("automock", originalId, id, url); | ||
| } | ||
| // every time the mock is registered, we remove the previous one from the cache | ||
| this.invalidateModuleById(id); | ||
| } | ||
| async importActual(_rawId, _importer, _callstack) { | ||
| throw new Error(`importActual is not implemented`); | ||
| } | ||
| async importMock(_rawId, _importer, _callstack) { | ||
| throw new Error(`importMock is not implemented`); | ||
| } | ||
| queueMock(id, importer, factoryOrOptions) { | ||
| const mockType = getMockType(factoryOrOptions); | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "mock", | ||
| id, | ||
| importer, | ||
| factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0, | ||
| type: mockType | ||
| }); | ||
| } | ||
| queueUnmock(id, importer) { | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "unmock", | ||
| id, | ||
| importer | ||
| }); | ||
| } | ||
| } | ||
| function getMockType(factoryOrOptions) { | ||
| if (!factoryOrOptions) return "automock"; | ||
| if (typeof factoryOrOptions === "function") return "manual"; | ||
| return factoryOrOptions.spy ? "autospy" : "automock"; | ||
| } | ||
| // unique id that is not available as "$bare_import" like "test" | ||
| // https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix | ||
| const prefixedBuiltins = new Set([ | ||
| "node:sea", | ||
| "node:sqlite", | ||
| "node:test", | ||
| "node:test/reporters" | ||
| ]); | ||
| const isWindows$1 = process.platform === "win32"; | ||
| // transform file url to id | ||
| // virtual:custom -> virtual:custom | ||
| // \0custom -> \0custom | ||
| // /root/id -> /id | ||
| // /root/id.js -> /id.js | ||
| // C:/root/id.js -> /id.js | ||
| // C:\root\id.js -> /id.js | ||
| // TODO: expose this in vite/module-runner | ||
| function normalizeModuleId(file) { | ||
| if (prefixedBuiltins.has(file)) return file; | ||
| // if it's not in the root, keep it as a path, not a URL | ||
| return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/"); | ||
| } | ||
| const windowsSlashRE = /\\/g; | ||
| function slash(p) { | ||
| return p.replace(windowsSlashRE, "/"); | ||
| } | ||
| function groupByConsecutiveAction(mocks) { | ||
| const groups = []; | ||
| for (const mock of mocks) { | ||
| const last = groups.at(-1); | ||
| if (last?.[0].action === mock.action) last.push(mock); | ||
| else groups.push([mock]); | ||
| } | ||
| return groups; | ||
| } | ||
| const multipleSlashRe = /^\/+/; | ||
| // module-runner incorrectly replaces file:///path with `///path` | ||
| function fixLeadingSlashes(id) { | ||
| if (id.startsWith("//")) return id.replace(multipleSlashRe, "/"); | ||
| return id; | ||
| } | ||
| // copied from vite | ||
| // https://github.com/vitejs/vite/blob/4417b4f305623b2850bd6ae6553834c017694672/packages/vite/src/shared/utils.ts | ||
| // https://github.com/vitejs/vite/blob/4417b4f305623b2850bd6ae6553834c017694672/packages/vite/src/node/utils.ts | ||
| const postfixRE = /[?#].*$/; | ||
| const trailingSeparatorRE = /[?&]$/; | ||
| function cleanUrl(url) { | ||
| return url.replace(postfixRE, ""); | ||
| } | ||
| function splitFileAndPostfix(path) { | ||
| const file = cleanUrl(path); | ||
| return { | ||
| file, | ||
| postfix: path.slice(file.length) | ||
| }; | ||
| } | ||
| function injectQuery(url, queryToInject) { | ||
| const { file, postfix } = splitFileAndPostfix(url); | ||
| return `${file}?${queryToInject}${postfix[0] === "?" ? `&${postfix.slice(1)}` : postfix}`; | ||
| } | ||
| function removeQuery(url, queryToRemove) { | ||
| return url.replace(new RegExp(`([?&])${queryToRemove}(?:&|$)`), "$1").replace(trailingSeparatorRE, ""); | ||
| } | ||
| const spyModulePath = resolve(distDir, "spy.js"); | ||
| class VitestMocker extends BareModuleMocker { | ||
| filterPublicKeys; | ||
| constructor(moduleRunner, options) { | ||
| super(options); | ||
| this.moduleRunner = moduleRunner; | ||
| this.options = options; | ||
| const context = this.options.context; | ||
| if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context); | ||
| const Symbol = this.primitives.Symbol; | ||
| this.filterPublicKeys = [ | ||
| "__esModule", | ||
| Symbol.asyncIterator, | ||
| Symbol.hasInstance, | ||
| Symbol.isConcatSpreadable, | ||
| Symbol.iterator, | ||
| Symbol.match, | ||
| Symbol.matchAll, | ||
| Symbol.replace, | ||
| Symbol.search, | ||
| Symbol.split, | ||
| Symbol.species, | ||
| Symbol.toPrimitive, | ||
| Symbol.toStringTag, | ||
| Symbol.unscopables | ||
| ]; | ||
| } | ||
| get evaluatedModules() { | ||
| return this.moduleRunner.evaluatedModules; | ||
| } | ||
| async initializeSpyModule() { | ||
| if (this.spyModule) return; | ||
| this.spyModule = await this.moduleRunner.import(spyModulePath); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(id) { | ||
| const mockId = this.getMockPath(id); | ||
| const node = this.evaluatedModules.getModuleById(mockId); | ||
| if (node) { | ||
| this.evaluatedModules.invalidateModule(node); | ||
| node.mockedExports = void 0; | ||
| } | ||
| } | ||
| ensureModule(id, url) { | ||
| const node = this.evaluatedModules.ensureModule(id, url); | ||
| // TODO | ||
| node.meta = { | ||
| id, | ||
| url, | ||
| code: "", | ||
| file: null, | ||
| invalidate: false | ||
| }; | ||
| return node; | ||
| } | ||
| async callFunctionMock(id, url, mock) { | ||
| const node = this.ensureModule(id, url); | ||
| if (node.exports) return node.exports; | ||
| const exports$1 = await mock.resolve(); | ||
| const moduleExports = new Proxy(exports$1, { get: (target, prop) => { | ||
| const val = target[prop]; | ||
| // 'then' can exist on non-Promise objects, need nested instanceof check for logic to work | ||
| if (prop === "then") { | ||
| if (target instanceof Promise) return target.then.bind(target); | ||
| } else if (!(prop in target)) { | ||
| if (this.filterPublicKeys.includes(prop)) return; | ||
| throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"? | ||
| If you need to partially mock a module, you can use "importOriginal" helper inside: | ||
| `, `vi.mock(import("${mock.raw}"), async (importOriginal) => { | ||
| const actual = await importOriginal() | ||
| return { | ||
| ...actual, | ||
| // your mocked methods | ||
| } | ||
| })`); | ||
| } | ||
| return val; | ||
| } }); | ||
| node.exports = moduleExports; | ||
| return moduleExports; | ||
| } | ||
| async importActual(rawId, importer, callstack) { | ||
| const { url } = await this.resolveId(rawId, importer); | ||
| const actualUrl = injectQuery(url, "_vitest_original"); | ||
| const node = await this.moduleRunner.fetchModule(actualUrl, importer); | ||
| return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true); | ||
| } | ||
| async importMock(rawId, importer) { | ||
| const { id, url, external } = await this.resolveId(rawId, importer); | ||
| let mock = this.getDependencyMock(id); | ||
| if (!mock) { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) mock = new RedirectedModule(rawId, id, rawId, redirect); | ||
| else mock = new AutomockedModule(rawId, id, rawId); | ||
| } | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const node = await this.moduleRunner.fetchModule(url, importer); | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true); | ||
| const Object = this.primitives.Object; | ||
| return this.mockObject(mod, Object.create(Object.prototype), mock.type); | ||
| } | ||
| if (mock.type === "manual") return this.callFunctionMock(id, url, mock); | ||
| const node = await this.moduleRunner.fetchModule(mock.redirect); | ||
| return this.moduleRunner.cachedRequest(mock.redirect, node, [importer], void 0, true); | ||
| } | ||
| async requestWithMockedModule(url, evaluatedNode, callstack, mock) { | ||
| return this._otel.$("vitest.mocker.evaluate", async (span) => { | ||
| const mockId = this.getMockPath(evaluatedNode.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": mockId, | ||
| "vitest.mock.type": mock.type, | ||
| "vitest.mock.id": mock.id, | ||
| "vitest.mock.url": mock.url, | ||
| "vitest.mock.raw": mock.raw | ||
| }); | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const cache = this.evaluatedModules.getModuleById(mockId); | ||
| if (cache && cache.mockedExports) return cache.mockedExports; | ||
| const Object = this.primitives.Object; | ||
| // we have to define a separate object that will copy all properties into itself | ||
| // and can't just use the same `exports` define automatically by Vite before the evaluator | ||
| const exports$1 = Object.create(null); | ||
| Object.defineProperty(exports$1, Symbol.toStringTag, { | ||
| value: "Module", | ||
| configurable: true, | ||
| writable: true | ||
| }); | ||
| const node = this.ensureModule(mockId, this.getMockPath(evaluatedNode.url)); | ||
| node.meta = evaluatedNode.meta; | ||
| node.file = evaluatedNode.file; | ||
| node.mockedExports = exports$1; | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, callstack, void 0, true); | ||
| this.mockObject(mod, exports$1, mock.type); | ||
| return exports$1; | ||
| } | ||
| if (mock.type === "manual" && !callstack.includes(mockId) && !callstack.includes(url)) try { | ||
| callstack.push(mockId); | ||
| // this will not work if user does Promise.all(import(), import()) | ||
| // we can also use AsyncLocalStorage to store callstack, but this won't work in the browser | ||
| // maybe we should improve mock API in the future? | ||
| this.mockContext.callstack = callstack; | ||
| return await this.callFunctionMock(mockId, this.getMockPath(url), mock); | ||
| } finally { | ||
| this.mockContext.callstack = null; | ||
| const indexMock = callstack.indexOf(mockId); | ||
| callstack.splice(indexMock, 1); | ||
| } | ||
| else if (mock.type === "redirect" && !callstack.includes(mock.redirect)) { | ||
| span.setAttribute("vitest.mock.redirect", mock.redirect); | ||
| return mock.redirect; | ||
| } | ||
| }); | ||
| } | ||
| async mockedRequest(url, evaluatedNode, callstack) { | ||
| const mock = this.getDependencyMock(evaluatedNode.id); | ||
| if (!mock) return; | ||
| return this.requestWithMockedModule(url, evaluatedNode, callstack, mock); | ||
| } | ||
| } | ||
| class VitestTransport { | ||
| constructor(options, evaluatedModules, callstacks) { | ||
| this.options = options; | ||
| this.evaluatedModules = evaluatedModules; | ||
| this.callstacks = callstacks; | ||
| } | ||
| async invoke(event) { | ||
| if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) }; | ||
| if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) }; | ||
| const { name, data } = event.data; | ||
| if (name === "getBuiltins") | ||
| // we return an empty array here to avoid client-side builtin check, | ||
| // as we need builtins to go through `fetchModule` | ||
| return { result: [] }; | ||
| if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) }; | ||
| try { | ||
| return { result: await this.options.fetchModule(...data) }; | ||
| } catch (cause) { | ||
| if (cause instanceof EnvironmentTeardownError) { | ||
| const [id, importer] = data; | ||
| let message = `Cannot load '${id}'${importer ? ` imported from ${importer}` : ""} after the environment was torn down. This is not a bug in Vitest.`; | ||
| const moduleNode = importer ? this.evaluatedModules.getModuleById(importer) : void 0; | ||
| const callstack = moduleNode ? this.callstacks.get(moduleNode) : void 0; | ||
| if (callstack) message += ` The last recorded callstack:\n- ${[ | ||
| ...callstack, | ||
| importer, | ||
| id | ||
| ].reverse().join("\n- ")}`; | ||
| const error = new EnvironmentTeardownError(message); | ||
| if (cause.stack) error.stack = cause.stack.replace(cause.message, error.message); | ||
| return { error }; | ||
| } | ||
| return { error: cause }; | ||
| } | ||
| } | ||
| } | ||
| const createNodeImportMeta = (modulePath) => { | ||
| if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`); | ||
| const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath); | ||
| const href = defaultMeta.url; | ||
| const importMetaResolver = createImportMetaResolver() ?? defaultMeta.resolve; | ||
| return { | ||
| ...defaultMeta, | ||
| main: false, | ||
| resolve(id, parent) { | ||
| return importMetaResolver(id, parent ?? href); | ||
| } | ||
| }; | ||
| }; | ||
| function createImportMetaResolver() { | ||
| if (!import.meta.resolve) return; | ||
| return (specifier, importer) => import.meta.resolve(specifier, importer); | ||
| } | ||
| // @ts-expect-error overriding private method | ||
| class VitestModuleRunner extends viteModuleRunner.ModuleRunner { | ||
| mocker; | ||
| moduleExecutionInfo; | ||
| _otel; | ||
| _callstacks; | ||
| constructor(vitestOptions) { | ||
| const options = vitestOptions; | ||
| const evaluatedModules = options.evaluatedModules; | ||
| const callstacks = /* @__PURE__ */ new WeakMap(); | ||
| const transport = new VitestTransport(options.transport, evaluatedModules, callstacks); | ||
| super({ | ||
| transport, | ||
| hmr: false, | ||
| evaluatedModules, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| createImportMeta: vitestOptions.createImportMeta | ||
| }, options.evaluator); | ||
| this.vitestOptions = vitestOptions; | ||
| this._callstacks = callstacks; | ||
| this._otel = vitestOptions.traces || new Traces({ enabled: false }); | ||
| this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo; | ||
| this.mocker = options.mocker || new VitestMocker(this, { | ||
| spyModule: options.spyModule, | ||
| context: options.vm?.context, | ||
| traces: this._otel, | ||
| resolveId: options.transport.resolveId, | ||
| get root() { | ||
| return options.getWorkerState().config.root; | ||
| }, | ||
| get moduleDirectories() { | ||
| return options.getWorkerState().config.deps.moduleDirectories || []; | ||
| }, | ||
| getCurrentTestFilepath() { | ||
| return options.getWorkerState().filepath; | ||
| } | ||
| }); | ||
| if (options.vm) options.vm.context.__vitest_mocker__ = this.mocker; | ||
| else Object.defineProperty(globalThis, "__vitest_mocker__", { | ||
| configurable: true, | ||
| writable: true, | ||
| value: this.mocker | ||
| }); | ||
| } | ||
| /** | ||
| * Vite checks that the module has exports emulating the Node.js behaviour, | ||
| * but Vitest is more relaxed. | ||
| * | ||
| * We should keep the Vite behavior when there is a `strict` flag. | ||
| * @internal | ||
| */ | ||
| processImport(exports$1) { | ||
| return exports$1; | ||
| } | ||
| async import(rawId) { | ||
| const resolved = await this._otel.$("vitest.module.resolve_id", { attributes: { "vitest.module.raw_id": rawId } }, async (span) => { | ||
| const result = await this.vitestOptions.transport.resolveId(rawId); | ||
| if (result) span.setAttributes({ | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.file": result.file, | ||
| "vitest.module.id": result.id | ||
| }); | ||
| return result; | ||
| }); | ||
| return super.import(resolved ? resolved.url : rawId); | ||
| } | ||
| async fetchModule(url, importer) { | ||
| return await this.cachedModule(url, importer); | ||
| } | ||
| _cachedRequest(url, module, callstack = [], metadata) { | ||
| // @ts-expect-error "cachedRequest" is private | ||
| return super.cachedRequest(url, module, callstack, metadata); | ||
| } | ||
| /** | ||
| * @internal | ||
| */ | ||
| async cachedRequest(url, mod, callstack = [], metadata, ignoreMock = false) { | ||
| // Track for a better error message if dynamic import is not resolved properly | ||
| this._callstacks.set(mod, callstack); | ||
| if (ignoreMock) return this._cachedRequest(url, mod, callstack, metadata); | ||
| let mocked; | ||
| if (mod.meta && "mockedModule" in mod.meta) { | ||
| const mockedModule = mod.meta.mockedModule; | ||
| const mockId = this.mocker.getMockPath(mod.id); | ||
| // bypass mock and force "importActual" behavior when: | ||
| // - mock was removed by doUnmock (stale mockedModule in meta) | ||
| // - self-import: mock factory/file is importing the module it's mocking | ||
| const isStale = !this.mocker.getDependencyMock(mod.id); | ||
| const isSelfImport = callstack.includes(mockId) || callstack.includes(url) || "redirect" in mockedModule && callstack.includes(mockedModule.redirect); | ||
| if (isStale || isSelfImport) { | ||
| const node = await this.fetchModule(injectQuery(url, "_vitest_original")); | ||
| return this._cachedRequest(node.url, node, callstack, metadata); | ||
| } | ||
| mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, mockedModule); | ||
| } else mocked = await this.mocker.mockedRequest(url, mod, callstack); | ||
| if (typeof mocked === "string") { | ||
| const node = await this.fetchModule(mocked); | ||
| return this._cachedRequest(mocked, node, callstack, metadata); | ||
| } | ||
| if (mocked != null && typeof mocked === "object") return mocked; | ||
| return this._cachedRequest(url, mod, callstack, metadata); | ||
| } | ||
| /** @internal */ | ||
| _invalidateSubTreeById(ids, invalidated = /* @__PURE__ */ new Set()) { | ||
| for (const id of ids) { | ||
| if (invalidated.has(id)) continue; | ||
| const node = this.evaluatedModules.getModuleById(id); | ||
| if (!node) continue; | ||
| invalidated.add(id); | ||
| const subIds = Array.from(this.evaluatedModules.idToModuleMap).filter(([, mod]) => mod.importers.has(id)).map(([key]) => key); | ||
| if (subIds.length) this._invalidateSubTreeById(subIds, invalidated); | ||
| this.evaluatedModules.invalidateModule(node); | ||
| } | ||
| } | ||
| } | ||
| const bareVitestRegexp = /^@?vitest(?:\/|$)/; | ||
| const normalizedDistDir = normalize(distDir); | ||
| const relativeIds = {}; | ||
| const externalizeMap = /* @__PURE__ */ new Map(); | ||
| // all Vitest imports always need to be externalized | ||
| function getCachedVitestImport(id, state) { | ||
| if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4); | ||
| if (externalizeMap.has(id)) return { | ||
| externalize: externalizeMap.get(id), | ||
| type: "module" | ||
| }; | ||
| // always externalize Vitest because we import from there before running tests | ||
| // so we already have it cached by Node.js | ||
| const root = state().config.root; | ||
| const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length)); | ||
| if (id.includes(distDir) || id.includes(normalizedDistDir)) { | ||
| const { file, postfix } = splitFileAndPostfix$1(id); | ||
| const externalize = id.startsWith("file://") ? id : `${pathToFileURL(file)}${postfix}`; | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) { | ||
| const { file, postfix } = splitFileAndPostfix$1(id); | ||
| const externalize = `${pathToFileURL(join(root, file))}${postfix}`; | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (bareVitestRegexp.test(id)) { | ||
| externalizeMap.set(id, id); | ||
| return { | ||
| externalize: id, | ||
| type: "module" | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| const { readFileSync } = fs__default; | ||
| const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__"; | ||
| const cwd = process.cwd(); | ||
| const isWindows = process.platform === "win32"; | ||
| function startVitestModuleRunner(options) { | ||
| const traces = options.traces; | ||
| const state = () => getSafeWorkerState() || options.state; | ||
| const rpc = () => state().rpc; | ||
| const environment = () => { | ||
| const environment = state().environment; | ||
| return environment.viteEnvironment || environment.name; | ||
| }; | ||
| const vm = options.context && options.externalModulesExecutor ? { | ||
| context: options.context, | ||
| externalModulesExecutor: options.externalModulesExecutor | ||
| } : void 0; | ||
| // A fresh worker pays one strictly sequential `fetch` round-trip per module | ||
| // in its test files' import graphs, even when the server processed all of | ||
| // them already. Ask the server ONCE per run request for everything it has on | ||
| // disk and answer those fetches locally. A file change invalidates the module | ||
| // server-side, dropping it from the snapshot of every subsequent run request, | ||
| // which keeps reused (isolate: false) workers in sync; an edit DURING a run | ||
| // was racy before this fast path existed and stays racy with it — the | ||
| // scheduled rerun always sees the fresh transform. | ||
| let warmModules; | ||
| let warmModulesContext; | ||
| function fetchWarmModules() { | ||
| const workerState = state(); | ||
| if (warmModulesContext !== workerState.ctx) { | ||
| warmModulesContext = workerState.ctx; | ||
| warmModules = rpc().fetchWarmModules(environment(), workerState.ctx.files.map((file) => file.filepath)).catch(() => null); | ||
| } | ||
| return warmModules; | ||
| } | ||
| const evaluator = options.evaluator || new VitestModuleEvaluator(vm, { | ||
| traces, | ||
| metaEnv: state().metaEnv, | ||
| evaluatedModules: options.evaluatedModules, | ||
| get moduleExecutionInfo() { | ||
| return state().moduleExecutionInfo; | ||
| }, | ||
| get interopDefault() { | ||
| return state().config.deps.interopDefault; | ||
| }, | ||
| get injectCjsGlobals() { | ||
| return state().config.injectCjsGlobals; | ||
| }, | ||
| getCurrentTestFilepath: () => state().filepath, | ||
| getterTracker: state().getterTracker | ||
| }); | ||
| const moduleRunner = new VitestModuleRunner({ | ||
| spyModule: options.spyModule, | ||
| evaluatedModules: options.evaluatedModules, | ||
| evaluator, | ||
| traces, | ||
| mocker: options.mocker, | ||
| transport: { | ||
| async fetchModule(id, importer, options) { | ||
| const resolvingModules = state().resolvingModules; | ||
| if (isWindows) { | ||
| if (id[1] === ":") { | ||
| // The drive letter is different for whatever reason, we need to normalize it to CWD | ||
| if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) id = (cwd[0].toUpperCase() === cwd[0] ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1); | ||
| // always mark absolute windows paths, otherwise Vite will externalize it | ||
| id = `/@id/${id}`; | ||
| } | ||
| } | ||
| const vitest = getCachedVitestImport(id, state); | ||
| if (vitest) return vitest; | ||
| // strip _vitest_original query added by importActual so that | ||
| // the plugin pipeline sees the original import id (e.g. virtual modules's load hook) | ||
| const isImportActual = id.includes("_vitest_original"); | ||
| if (isImportActual) id = removeQuery(id, "_vitest_original"); | ||
| const rawId = unwrapId(id); | ||
| resolvingModules.add(rawId); | ||
| try { | ||
| if (VitestMocker.pendingIds.length) await moduleRunner.mocker.resolveMocks(); | ||
| if (!isImportActual) { | ||
| const resolvedMock = moduleRunner.mocker.getDependencyMockByUrl(id); | ||
| if (resolvedMock?.type === "manual" || resolvedMock?.type === "redirect") return { | ||
| code: "", | ||
| file: null, | ||
| id: resolvedMock.id, | ||
| url: resolvedMock.url, | ||
| invalidate: false, | ||
| mockedModule: resolvedMock | ||
| }; | ||
| } | ||
| if (isBuiltin(rawId)) return { | ||
| externalize: rawId, | ||
| type: "builtin" | ||
| }; | ||
| if (isBrowserExternal(rawId)) return { | ||
| externalize: toBuiltin(rawId), | ||
| type: "builtin" | ||
| }; | ||
| // if module is invalidated, the worker will be recreated, | ||
| // so cached is always true in a single worker | ||
| if (!isImportActual && options?.cached) return { cache: true }; | ||
| // only dependency fetches consult the snapshot: by the time the | ||
| // first dependency is requested, the entry file is transformed and | ||
| // its import graph is connected on the server, so the snapshot | ||
| // actually covers the file's transitive dependencies | ||
| if (importer != null) { | ||
| const warm = await fetchWarmModules(); | ||
| // the null prototype is not preserved by the IPC serialization, so | ||
| // ids like "constructor" must not fall through to Object.prototype | ||
| const warmResult = warm && (Object.hasOwn(warm, id) ? warm[id] : Object.hasOwn(warm, rawId) ? warm[rawId] : void 0); | ||
| if (warmResult) if ("tmp" in warmResult) try { | ||
| return { | ||
| code: readFileSync(warmResult.tmp, "utf-8"), | ||
| ...warmResult | ||
| }; | ||
| } catch {} | ||
| else return warmResult; | ||
| } | ||
| const otelCarrier = traces?.getContextCarrier(); | ||
| const result = await rpc().fetch(id, importer, environment(), options, otelCarrier); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| return result; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause != null && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url") || typeof cause?.message === "string" && cause.message.startsWith("Cannot find module '")) { | ||
| const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from ${importer}` : ""}`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| throw cause; | ||
| } finally { | ||
| resolvingModules.delete(rawId); | ||
| } | ||
| }, | ||
| resolveId(id, importer) { | ||
| return rpc().resolve(id, importer, environment()); | ||
| } | ||
| }, | ||
| getWorkerState: state, | ||
| vm, | ||
| createImportMeta: options.createImportMeta | ||
| }); | ||
| return moduleRunner; | ||
| } | ||
| // SEE https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/interfaces.js | ||
| const LIVING_KEYS = [ | ||
| "DOMException", | ||
| "EventTarget", | ||
| "NamedNodeMap", | ||
| "Node", | ||
| "Attr", | ||
| "Element", | ||
| "DocumentFragment", | ||
| "DOMImplementation", | ||
| "Document", | ||
| "XMLDocument", | ||
| "CharacterData", | ||
| "Text", | ||
| "CDATASection", | ||
| "ProcessingInstruction", | ||
| "Comment", | ||
| "DocumentType", | ||
| "NodeList", | ||
| "RadioNodeList", | ||
| "HTMLCollection", | ||
| "HTMLOptionsCollection", | ||
| "DOMStringMap", | ||
| "DOMTokenList", | ||
| "StyleSheetList", | ||
| "HTMLElement", | ||
| "HTMLHeadElement", | ||
| "HTMLTitleElement", | ||
| "HTMLBaseElement", | ||
| "HTMLLinkElement", | ||
| "HTMLMetaElement", | ||
| "HTMLStyleElement", | ||
| "HTMLBodyElement", | ||
| "HTMLHeadingElement", | ||
| "HTMLParagraphElement", | ||
| "HTMLHRElement", | ||
| "HTMLPreElement", | ||
| "HTMLUListElement", | ||
| "HTMLOListElement", | ||
| "HTMLLIElement", | ||
| "HTMLMenuElement", | ||
| "HTMLDListElement", | ||
| "HTMLDivElement", | ||
| "HTMLAnchorElement", | ||
| "HTMLAreaElement", | ||
| "HTMLBRElement", | ||
| "HTMLButtonElement", | ||
| "HTMLCanvasElement", | ||
| "HTMLDataElement", | ||
| "HTMLDataListElement", | ||
| "HTMLDetailsElement", | ||
| "HTMLDialogElement", | ||
| "HTMLDirectoryElement", | ||
| "HTMLFieldSetElement", | ||
| "HTMLFontElement", | ||
| "HTMLFormElement", | ||
| "HTMLHtmlElement", | ||
| "HTMLImageElement", | ||
| "HTMLInputElement", | ||
| "HTMLLabelElement", | ||
| "HTMLLegendElement", | ||
| "HTMLMapElement", | ||
| "HTMLMarqueeElement", | ||
| "HTMLMediaElement", | ||
| "HTMLMeterElement", | ||
| "HTMLModElement", | ||
| "HTMLOptGroupElement", | ||
| "HTMLOptionElement", | ||
| "HTMLOutputElement", | ||
| "HTMLPictureElement", | ||
| "HTMLProgressElement", | ||
| "HTMLQuoteElement", | ||
| "HTMLScriptElement", | ||
| "HTMLSelectElement", | ||
| "HTMLSlotElement", | ||
| "HTMLSourceElement", | ||
| "HTMLSpanElement", | ||
| "HTMLTableCaptionElement", | ||
| "HTMLTableCellElement", | ||
| "HTMLTableColElement", | ||
| "HTMLTableElement", | ||
| "HTMLTimeElement", | ||
| "HTMLTableRowElement", | ||
| "HTMLTableSectionElement", | ||
| "HTMLTemplateElement", | ||
| "HTMLTextAreaElement", | ||
| "HTMLUnknownElement", | ||
| "HTMLFrameElement", | ||
| "HTMLFrameSetElement", | ||
| "HTMLIFrameElement", | ||
| "HTMLEmbedElement", | ||
| "HTMLObjectElement", | ||
| "HTMLParamElement", | ||
| "HTMLVideoElement", | ||
| "HTMLAudioElement", | ||
| "HTMLTrackElement", | ||
| "HTMLFormControlsCollection", | ||
| "SVGElement", | ||
| "SVGGraphicsElement", | ||
| "SVGSVGElement", | ||
| "SVGTitleElement", | ||
| "SVGAnimatedString", | ||
| "SVGNumber", | ||
| "SVGStringList", | ||
| "Event", | ||
| "CloseEvent", | ||
| "CustomEvent", | ||
| "MessageEvent", | ||
| "ErrorEvent", | ||
| "HashChangeEvent", | ||
| "PopStateEvent", | ||
| "StorageEvent", | ||
| "ProgressEvent", | ||
| "PageTransitionEvent", | ||
| "SubmitEvent", | ||
| "UIEvent", | ||
| "FocusEvent", | ||
| "InputEvent", | ||
| "MouseEvent", | ||
| "KeyboardEvent", | ||
| "TouchEvent", | ||
| "CompositionEvent", | ||
| "WheelEvent", | ||
| "BarProp", | ||
| "External", | ||
| "Location", | ||
| "History", | ||
| "Screen", | ||
| "Crypto", | ||
| "Performance", | ||
| "Navigator", | ||
| "PluginArray", | ||
| "MimeTypeArray", | ||
| "Plugin", | ||
| "MimeType", | ||
| "FileReader", | ||
| "FormData", | ||
| "Blob", | ||
| "File", | ||
| "FileList", | ||
| "ValidityState", | ||
| "DOMParser", | ||
| "XMLSerializer", | ||
| "XMLHttpRequestEventTarget", | ||
| "XMLHttpRequestUpload", | ||
| "XMLHttpRequest", | ||
| "WebSocket", | ||
| "NodeFilter", | ||
| "NodeIterator", | ||
| "TreeWalker", | ||
| "AbstractRange", | ||
| "Range", | ||
| "StaticRange", | ||
| "Selection", | ||
| "Storage", | ||
| "CustomElementRegistry", | ||
| "ShadowRoot", | ||
| "MutationObserver", | ||
| "MutationRecord", | ||
| "Uint8Array", | ||
| "Uint16Array", | ||
| "Uint32Array", | ||
| "Uint8ClampedArray", | ||
| "Int8Array", | ||
| "Int16Array", | ||
| "Int32Array", | ||
| "Float32Array", | ||
| "Float64Array", | ||
| "ArrayBuffer", | ||
| "DOMRectReadOnly", | ||
| "DOMRect", | ||
| "Image", | ||
| "Audio", | ||
| "Option", | ||
| "CSS" | ||
| ]; | ||
| const OTHER_KEYS = [ | ||
| "addEventListener", | ||
| "alert", | ||
| "blur", | ||
| "cancelAnimationFrame", | ||
| "close", | ||
| "confirm", | ||
| "createPopup", | ||
| "dispatchEvent", | ||
| "document", | ||
| "focus", | ||
| "frames", | ||
| "getComputedStyle", | ||
| "history", | ||
| "innerHeight", | ||
| "innerWidth", | ||
| "length", | ||
| "localStorage", | ||
| "location", | ||
| "matchMedia", | ||
| "moveBy", | ||
| "moveTo", | ||
| "name", | ||
| "navigator", | ||
| "open", | ||
| "outerHeight", | ||
| "outerWidth", | ||
| "pageXOffset", | ||
| "pageYOffset", | ||
| "parent", | ||
| "postMessage", | ||
| "print", | ||
| "prompt", | ||
| "removeEventListener", | ||
| "requestAnimationFrame", | ||
| "resizeBy", | ||
| "resizeTo", | ||
| "screen", | ||
| "screenLeft", | ||
| "screenTop", | ||
| "screenX", | ||
| "screenY", | ||
| "scroll", | ||
| "scrollBy", | ||
| "scrollLeft", | ||
| "scrollTo", | ||
| "scrollTop", | ||
| "scrollX", | ||
| "scrollY", | ||
| "self", | ||
| "sessionStorage", | ||
| "stop", | ||
| "top", | ||
| "Window", | ||
| "window" | ||
| ]; | ||
| const KEYS = LIVING_KEYS.concat(OTHER_KEYS); | ||
| const skipKeys = [ | ||
| "window", | ||
| "self", | ||
| "top", | ||
| "parent" | ||
| ]; | ||
| function getWindowKeys(global, win, additionalKeys = []) { | ||
| const keysArray = [...additionalKeys, ...KEYS]; | ||
| return new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => { | ||
| if (skipKeys.includes(k)) return false; | ||
| if (k in global) return keysArray.includes(k); | ||
| return true; | ||
| })); | ||
| } | ||
| function isClassLikeName(name) { | ||
| return name[0] === name[0].toUpperCase(); | ||
| } | ||
| function populateGlobal(global, win, options = {}) { | ||
| const { bindFunctions = false } = options; | ||
| const keys = getWindowKeys(global, win, options.additionalKeys); | ||
| const originals = /* @__PURE__ */ new Map(); | ||
| const overriddenKeys = new Set([...KEYS, ...options.additionalKeys || []]); | ||
| const overrideObject = /* @__PURE__ */ new Map(); | ||
| for (const key of keys) { | ||
| const boundFunction = bindFunctions && typeof win[key] === "function" && !isClassLikeName(key) && win[key].bind(win); | ||
| if (overriddenKeys.has(key) && key in global) { | ||
| // capture the descriptor instead of the value to avoid invoking native | ||
| // lazy getters such as Node's `localStorage`, which warns when accessed | ||
| // without `--localstorage-file` | ||
| const descriptor = Object.getOwnPropertyDescriptor(global, key) ?? { | ||
| value: global[key], | ||
| configurable: true, | ||
| writable: true, | ||
| enumerable: true | ||
| }; | ||
| originals.set(key, descriptor); | ||
| } | ||
| Object.defineProperty(global, key, { | ||
| get() { | ||
| if (overrideObject.has(key)) return overrideObject.get(key); | ||
| if (boundFunction) return boundFunction; | ||
| return win[key]; | ||
| }, | ||
| set(v) { | ||
| overrideObject.set(key, v); | ||
| // propagate changes to underlying window implementation, | ||
| // which can affect other window API behavior internally, e.g. | ||
| // updating `innerWidth` affects `matchMedia("(max-width: *)")` on happy-dom. | ||
| win[key] = v; | ||
| }, | ||
| configurable: true | ||
| }); | ||
| } | ||
| global.window = global; | ||
| global.self = global; | ||
| global.top = global; | ||
| global.parent = global; | ||
| if (global.global) global.global = global; | ||
| // rewrite defaultView to reference the same global context | ||
| if (global.document && global.document.defaultView) Object.defineProperty(global.document, "defaultView", { | ||
| get: () => global, | ||
| enumerable: true, | ||
| configurable: true | ||
| }); | ||
| skipKeys.forEach((k) => keys.add(k)); | ||
| return { | ||
| keys, | ||
| skipKeys, | ||
| originals | ||
| }; | ||
| } | ||
| var edge = { | ||
| name: "edge-runtime", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const vm = new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| return context; | ||
| } }); | ||
| return { | ||
| getVmContext() { | ||
| return vm.context; | ||
| }, | ||
| teardown() { | ||
| // nothing to teardown | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const { keys, originals } = populateGlobal(global, new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| KEYS.forEach((key) => { | ||
| if (key in global) context[key] = global[key]; | ||
| }); | ||
| return context; | ||
| } }).context, { bindFunctions: true }); | ||
| return { teardown(global) { | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((d, k) => Object.defineProperty(global, k, d)); | ||
| } }; | ||
| } | ||
| }; | ||
| async function teardownWindow(win) { | ||
| if (win.close && win.happyDOM.abort) { | ||
| await win.happyDOM.abort(); | ||
| win.close(); | ||
| } else win.happyDOM.cancelAsync(); | ||
| } | ||
| var happy = { | ||
| name: "happy-dom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ happyDOM = {} }) { | ||
| const { Window } = await import('happy-dom'); | ||
| let win = new Window({ | ||
| ...happyDOM, | ||
| console: console && globalThis.console ? globalThis.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| win.Buffer = Buffer; | ||
| // inject structuredClone if it exists | ||
| if (typeof structuredClone !== "undefined" && !win.structuredClone) win.structuredClone = structuredClone; | ||
| return { | ||
| getVmContext() { | ||
| return win; | ||
| }, | ||
| async teardown() { | ||
| await teardownWindow(win); | ||
| win = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { happyDOM = {} }) { | ||
| // happy-dom v3 introduced a breaking change to Window, but | ||
| // provides GlobalWindow as a way to use previous behaviour | ||
| const { Window, GlobalWindow } = await import('happy-dom'); | ||
| const win = new (GlobalWindow || Window)({ | ||
| ...happyDOM, | ||
| console: console && global.console ? global.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| const { keys, originals } = populateGlobal(global, win, { | ||
| bindFunctions: true, | ||
| additionalKeys: [ | ||
| "Request", | ||
| "Response", | ||
| "MessagePort", | ||
| "fetch", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URL", | ||
| "URLSearchParams", | ||
| "FormData" | ||
| ] | ||
| }); | ||
| return { async teardown(global) { | ||
| await teardownWindow(win); | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((d, k) => Object.defineProperty(global, k, d)); | ||
| } }; | ||
| } | ||
| }; | ||
| function catchWindowErrors(window) { | ||
| let userErrorListenerCount = 0; | ||
| function throwUnhandlerError(e) { | ||
| if (userErrorListenerCount === 0 && e.error != null) { | ||
| e.preventDefault(); | ||
| process.emit("uncaughtException", e.error); | ||
| } | ||
| } | ||
| const addEventListener = window.addEventListener.bind(window); | ||
| const removeEventListener = window.removeEventListener.bind(window); | ||
| window.addEventListener("error", throwUnhandlerError); | ||
| window.addEventListener = function(...args) { | ||
| if (args[0] === "error") userErrorListenerCount++; | ||
| return addEventListener.apply(this, args); | ||
| }; | ||
| window.removeEventListener = function(...args) { | ||
| if (args[0] === "error" && userErrorListenerCount) userErrorListenerCount--; | ||
| return removeEventListener.apply(this, args); | ||
| }; | ||
| return function clearErrorHandlers() { | ||
| window.removeEventListener("error", throwUnhandlerError); | ||
| }; | ||
| } | ||
| let NodeFormData_; | ||
| let NodeBlob_; | ||
| let NodeRequest_; | ||
| var jsdom = { | ||
| name: "jsdom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| let dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const clearWindowErrors = catchWindowErrors(dom.window); | ||
| const utils = createCompatUtils(dom.window); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| dom.window.Buffer = Buffer; | ||
| dom.window.jsdom = dom; | ||
| dom.window.Request = createCompatRequest(utils); | ||
| dom.window.URL = createJSDOMCompatURL(utils); | ||
| for (const name of [ | ||
| "structuredClone", | ||
| "BroadcastChannel", | ||
| "MessageChannel", | ||
| "MessagePort", | ||
| "TextEncoder", | ||
| "TextDecoder" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined" && typeof dom.window[name] === "undefined") dom.window[name] = value; | ||
| } | ||
| for (const name of [ | ||
| "fetch", | ||
| "Response", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URLSearchParams" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined") dom.window[name] = value; | ||
| } | ||
| return { | ||
| getVmContext() { | ||
| return dom.getInternalVMContext(); | ||
| }, | ||
| teardown() { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| dom = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| const dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }); | ||
| const clearWindowErrors = catchWindowErrors(global); | ||
| const utils = createCompatUtils(dom.window); | ||
| global.jsdom = dom; | ||
| global.Request = createCompatRequest(utils); | ||
| global.URL = createJSDOMCompatURL(utils); | ||
| return { teardown(global) { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| delete global.jsdom; | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((d, k) => Object.defineProperty(global, k, d)); | ||
| } }; | ||
| } | ||
| }; | ||
| function createCompatRequest(utils) { | ||
| class Request extends NodeRequest_ { | ||
| constructor(...args) { | ||
| const [input, init] = args; | ||
| if (init?.body != null) { | ||
| const compatInit = { ...init }; | ||
| if (init.body instanceof utils.window.Blob) compatInit.body = utils.makeCompatBlob(init.body); | ||
| if (init.body instanceof utils.window.FormData) compatInit.body = utils.makeCompatFormData(init.body); | ||
| super(input, compatInit); | ||
| } else super(...args); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof NodeRequest_; | ||
| } | ||
| } | ||
| return Request; | ||
| } | ||
| function createJSDOMCompatURL(utils) { | ||
| class URL extends URL$1 { | ||
| static createObjectURL(blob) { | ||
| if (blob instanceof utils.window.Blob) { | ||
| const compatBlob = utils.makeCompatBlob(blob); | ||
| return URL$1.createObjectURL(compatBlob); | ||
| } | ||
| return URL$1.createObjectURL(blob); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof URL$1; | ||
| } | ||
| } | ||
| return URL; | ||
| } | ||
| function createCompatUtils(window) { | ||
| // this returns a hidden Symbol(impl) | ||
| // this is cursed, and jsdom should just implement fetch API itself | ||
| const implSymbol = Object.getOwnPropertySymbols(Object.getOwnPropertyDescriptors(new window.Blob()))[0]; | ||
| const utils = { | ||
| window, | ||
| makeCompatFormData(formData) { | ||
| const nodeFormData = new NodeFormData_(); | ||
| formData.forEach((value, key) => { | ||
| if (value instanceof window.Blob) nodeFormData.append(key, utils.makeCompatBlob(value)); | ||
| else nodeFormData.append(key, value); | ||
| }); | ||
| return nodeFormData; | ||
| }, | ||
| makeCompatBlob(blob) { | ||
| const buffer = blob[implSymbol]._buffer; | ||
| return new NodeBlob_([buffer], { type: blob.type }); | ||
| } | ||
| }; | ||
| return utils; | ||
| } | ||
| function patchAddEventListener(window) { | ||
| const abortControllers = /* @__PURE__ */ new WeakMap(); | ||
| const JSDOMAbortSignal = window.AbortSignal; | ||
| const JSDOMAbortController = window.AbortController; | ||
| const originalAddEventListener = window.EventTarget.prototype.addEventListener; | ||
| function getJsdomAbortController(signal) { | ||
| if (!abortControllers.has(signal)) { | ||
| const jsdomAbortController = new JSDOMAbortController(); | ||
| signal.addEventListener("abort", () => { | ||
| jsdomAbortController.abort(signal.reason); | ||
| }); | ||
| abortControllers.set(signal, jsdomAbortController); | ||
| } | ||
| return abortControllers.get(signal); | ||
| } | ||
| window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) { | ||
| if (typeof options === "object" && options?.signal != null) { | ||
| const { signal, ...otherOptions } = options; | ||
| // - this happens because AbortSignal is provided by Node.js, | ||
| // but jsdom APIs require jsdom's AbortSignal, while Node APIs | ||
| // (like fetch and Request) require a Node.js AbortSignal | ||
| // - disable narrow typing with "as any" because we need it later | ||
| if (!(signal instanceof JSDOMAbortSignal)) { | ||
| const jsdomCompatOptions = Object.create(null); | ||
| Object.assign(jsdomCompatOptions, otherOptions); | ||
| jsdomCompatOptions.signal = getJsdomAbortController(signal).signal; | ||
| return originalAddEventListener.call(this, type, callback, jsdomCompatOptions); | ||
| } | ||
| } | ||
| return originalAddEventListener.call(this, type, callback, options); | ||
| }; | ||
| return () => { | ||
| window.EventTarget.prototype.addEventListener = originalAddEventListener; | ||
| }; | ||
| } | ||
| // some globals we do not want, either because deprecated or we set it ourselves | ||
| const denyList = new Set([ | ||
| "GLOBAL", | ||
| "root", | ||
| "global", | ||
| "Buffer", | ||
| "ArrayBuffer", | ||
| "Uint8Array" | ||
| ]); | ||
| const nodeGlobals = /* @__PURE__ */ new Map(); | ||
| function populateNodeGlobals() { | ||
| if (nodeGlobals.size !== 0) return; | ||
| const names = Object.getOwnPropertyNames(globalThis); | ||
| const length = names.length; | ||
| for (let i = 0; i < length; i++) { | ||
| const globalName = names[i]; | ||
| if (!denyList.has(globalName)) { | ||
| const descriptor = Object.getOwnPropertyDescriptor(globalThis, globalName); | ||
| if (!descriptor) throw new Error(`No property descriptor for ${globalName}, this is a bug in Vitest.`); | ||
| nodeGlobals.set(globalName, descriptor); | ||
| } | ||
| } | ||
| } | ||
| var node = { | ||
| name: "node", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| populateNodeGlobals(); | ||
| const vm = await import('node:vm'); | ||
| let context = vm.createContext(); | ||
| let global = vm.runInContext("this", context); | ||
| const contextGlobals = new Set(Object.getOwnPropertyNames(global)); | ||
| for (const [nodeGlobalsKey, descriptor] of nodeGlobals) if (!contextGlobals.has(nodeGlobalsKey)) if (descriptor.configurable) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| get() { | ||
| // @ts-expect-error: no index signature | ||
| const val = globalThis[nodeGlobalsKey]; | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: descriptor.writable === true || nodeGlobalsKey === "performance" | ||
| }); | ||
| return val; | ||
| }, | ||
| set(val) { | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: true | ||
| }); | ||
| } | ||
| }); | ||
| else if ("value" in descriptor) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| value: descriptor.value, | ||
| writable: descriptor.writable | ||
| }); | ||
| else Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| get: descriptor.get, | ||
| set: descriptor.set | ||
| }); | ||
| global.global = global; | ||
| global.Buffer = Buffer; | ||
| global.ArrayBuffer = ArrayBuffer; | ||
| // TextEncoder (global or via 'util') references a Uint8Array constructor | ||
| // different than the global one used by users in tests. This makes sure the | ||
| // same constructor is referenced by both. | ||
| global.Uint8Array = Uint8Array; | ||
| return { | ||
| getVmContext() { | ||
| return context; | ||
| }, | ||
| teardown() { | ||
| context = void 0; | ||
| global = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| global.console.Console = Console; | ||
| return { teardown(global) { | ||
| delete global.console.Console; | ||
| } }; | ||
| } | ||
| }; | ||
| const environments = { | ||
| node, | ||
| jsdom, | ||
| "happy-dom": happy, | ||
| "edge-runtime": edge | ||
| }; | ||
| export { BareModuleMocker as B, VITEST_VM_CONTEXT_SYMBOL as V, VitestModuleRunner as a, VitestTransport as b, createNodeImportMeta as c, environments as e, normalizeModuleId as n, populateGlobal as p, startVitestModuleRunner as s }; |
| import { y } from './tinyrainbow.Ht9iggcq.js'; | ||
| function _mergeNamespaces$1(n, m) { | ||
| m.forEach(function(e) { | ||
| e && typeof e !== "string" && !Array.isArray(e) && Object.keys(e).forEach(function(k) { | ||
| if (k !== "default" && !(k in n)) { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function() { | ||
| return e[k]; | ||
| } | ||
| }); | ||
| } | ||
| }); | ||
| }); | ||
| return Object.freeze(n); | ||
| } | ||
| function getKeysOfEnumerableProperties(object, compareKeys) { | ||
| const rawKeys = Object.keys(object); | ||
| const keys = compareKeys === null ? rawKeys : rawKeys.sort(compareKeys); | ||
| if (Object.getOwnPropertySymbols) { | ||
| for (const symbol of Object.getOwnPropertySymbols(object)) if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) keys.push(symbol); | ||
| } | ||
| return keys; | ||
| } | ||
| /** | ||
| * Return entries (for example, of a map) | ||
| * with spacing, indentation, and comma | ||
| * without surrounding punctuation (for example, braces) | ||
| */ | ||
| function printIteratorEntries(iterator, config, indentation, depth, refs, printer, separator = ": ", length) { | ||
| let result = ""; | ||
| let width = 0; | ||
| let current = iterator.next(); | ||
| if (!current.done) { | ||
| result += config.spacingOuter; | ||
| const indentationNext = indentation + config.indent; | ||
| while (!current.done) { | ||
| result += indentationNext; | ||
| if (width++ === config.maxWidth) { | ||
| result += typeof length === "number" ? `…(${length - width + 1})` : "…"; | ||
| break; | ||
| } | ||
| const name = printer(current.value[0], config, indentationNext, depth, refs); | ||
| const value = printer(current.value[1], config, indentationNext, depth, refs); | ||
| result += name + separator + value; | ||
| current = iterator.next(); | ||
| if (!current.done) result += `,${config.spacingInner}`; | ||
| else if (!config.min) result += ","; | ||
| } | ||
| result += config.spacingOuter + indentation; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Return values (for example, of a set) | ||
| * with spacing, indentation, and comma | ||
| * without surrounding punctuation (braces or brackets) | ||
| */ | ||
| function printIteratorValues(iterator, config, indentation, depth, refs, printer, length) { | ||
| let result = ""; | ||
| let width = 0; | ||
| let current = iterator.next(); | ||
| if (!current.done) { | ||
| result += config.spacingOuter; | ||
| const indentationNext = indentation + config.indent; | ||
| while (!current.done) { | ||
| result += indentationNext; | ||
| if (width++ === config.maxWidth) { | ||
| result += typeof length === "number" ? `…(${length - width + 1})` : "…"; | ||
| break; | ||
| } | ||
| result += printer(current.value, config, indentationNext, depth, refs); | ||
| current = iterator.next(); | ||
| if (!current.done) result += `,${config.spacingInner}`; | ||
| else if (!config.min) result += ","; | ||
| } | ||
| result += config.spacingOuter + indentation; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Return items (for example, of an array) | ||
| * with spacing, indentation, and comma | ||
| * without surrounding punctuation (for example, brackets) | ||
| */ | ||
| function printListItems(list, config, indentation, depth, refs, printer) { | ||
| let result = ""; | ||
| list = list instanceof ArrayBuffer ? new DataView(list) : list; | ||
| const isDataView = (l) => l instanceof DataView; | ||
| const length = isDataView(list) ? list.byteLength : list.length; | ||
| if (length > 0) { | ||
| result += config.spacingOuter; | ||
| const indentationNext = indentation + config.indent; | ||
| for (let i = 0; i < length; i++) { | ||
| result += indentationNext; | ||
| if (i === config.maxWidth) { | ||
| result += `…(${length - i})`; | ||
| break; | ||
| } | ||
| if (isDataView(list) || i in list) result += printer(isDataView(list) ? list.getInt8(i) : list[i], config, indentationNext, depth, refs); | ||
| if (i < length - 1) result += `,${config.spacingInner}`; | ||
| else if (!config.min) result += ","; | ||
| } | ||
| result += config.spacingOuter + indentation; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Return properties of an object | ||
| * with spacing, indentation, and comma | ||
| * without surrounding punctuation (for example, braces) | ||
| */ | ||
| function printObjectProperties(val, config, indentation, depth, refs, printer, compareKeysOverride = config.compareKeys) { | ||
| let result = ""; | ||
| const keys = getKeysOfEnumerableProperties(val, compareKeysOverride); | ||
| if (keys.length > 0) { | ||
| result += config.spacingOuter; | ||
| const indentationNext = indentation + config.indent; | ||
| for (let i = 0; i < keys.length; i++) { | ||
| result += indentationNext; | ||
| if (i === config.maxWidth) { | ||
| result += `…(${keys.length - i})`; | ||
| break; | ||
| } | ||
| const key = keys[i]; | ||
| const name = !config.quoteKeys && isUnquotableKey(key) ? key : printer(key, config, indentationNext, depth, refs); | ||
| const value = printer(val[key], config, indentationNext, depth, refs); | ||
| result += `${name}: ${value}`; | ||
| if (i < keys.length - 1) result += `,${config.spacingInner}`; | ||
| else if (!config.min) result += ","; | ||
| } | ||
| result += config.spacingOuter + indentation; | ||
| } | ||
| return result; | ||
| } | ||
| // https://github.com/nodejs/node/blob/61102cdbb3d59155ad5bb4fc9419627a31e63f7a/lib/internal/util/inspect.js#L249 | ||
| // /^[a-zA-Z_][a-zA-Z_0-9]*$/ | ||
| const keyStrRegExp = /^[a-z_]\w*$/i; | ||
| function isUnquotableKey(key) { | ||
| return typeof key === "string" && key !== "__proto__" && keyStrRegExp.test(key); | ||
| } | ||
| const asymmetricMatcher = typeof Symbol === "function" && Symbol.for ? Symbol.for("jest.asymmetricMatcher") : 1267621; | ||
| const SPACE$2 = " "; | ||
| const serialize$5 = (val, config, indentation, depth, refs, printer) => { | ||
| const stringedValue = val.toString(); | ||
| if (stringedValue === "ArrayContaining" || stringedValue === "ArrayNotContaining") { | ||
| if (++depth > config.maxDepth) return `[${stringedValue}]`; | ||
| return `${stringedValue + SPACE$2}[${printListItems(val.sample, config, indentation, depth, refs, printer)}]`; | ||
| } | ||
| if (stringedValue === "ObjectContaining" || stringedValue === "ObjectNotContaining") { | ||
| if (++depth > config.maxDepth) return `[${stringedValue}]`; | ||
| return `${stringedValue + SPACE$2}{${printObjectProperties(val.sample, config, indentation, depth, refs, printer)}}`; | ||
| } | ||
| if (stringedValue === "StringMatching" || stringedValue === "StringNotMatching") return stringedValue + SPACE$2 + printer(val.sample, config, indentation, depth, refs); | ||
| if (stringedValue === "StringContaining" || stringedValue === "StringNotContaining") return stringedValue + SPACE$2 + printer(val.sample, config, indentation, depth, refs); | ||
| if (typeof val.toAsymmetricMatcher !== "function") throw new TypeError(`Asymmetric matcher ${val.constructor.name} does not implement toAsymmetricMatcher()`); | ||
| return val.toAsymmetricMatcher(); | ||
| }; | ||
| const test$5 = (val) => val && val.$$typeof === asymmetricMatcher; | ||
| const plugin$5 = { | ||
| serialize: serialize$5, | ||
| test: test$5 | ||
| }; | ||
| const SPACE$1 = " "; | ||
| const OBJECT_NAMES = new Set(["DOMStringMap", "NamedNodeMap"]); | ||
| const ARRAY_REGEXP = /^(?:HTML\w*Collection|NodeList)$/; | ||
| function testName(name) { | ||
| return OBJECT_NAMES.has(name) || ARRAY_REGEXP.test(name); | ||
| } | ||
| const test$4 = (val) => val && val.constructor && !!val.constructor.name && testName(val.constructor.name); | ||
| function isNamedNodeMap(collection) { | ||
| return collection.constructor.name === "NamedNodeMap"; | ||
| } | ||
| const serialize$4 = (collection, config, indentation, depth, refs, printer) => { | ||
| const name = collection.constructor.name; | ||
| if (++depth > config.maxDepth) return `[${name}]`; | ||
| return (config.min ? "" : name + SPACE$1) + (OBJECT_NAMES.has(name) ? `{${printObjectProperties(isNamedNodeMap(collection) ? [...collection].reduce((props, attribute) => { | ||
| props[attribute.name] = attribute.value; | ||
| return props; | ||
| }, {}) : { ...collection }, config, indentation, depth, refs, printer)}}` : `[${printListItems([...collection], config, indentation, depth, refs, printer)}]`); | ||
| }; | ||
| const plugin$4 = { | ||
| serialize: serialize$4, | ||
| test: test$4 | ||
| }; | ||
| /** | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
| function escapeHTML(str) { | ||
| return str.replaceAll("<", "<").replaceAll(">", ">"); | ||
| } | ||
| // Return empty string if keys is empty. | ||
| function printProps(keys, props, config, indentation, depth, refs, printer) { | ||
| const indentationNext = indentation + config.indent; | ||
| const colors = config.colors; | ||
| return keys.map((key) => { | ||
| const value = props[key]; | ||
| // hidden injected value that should not be printed | ||
| if (typeof value === "string" && value[0] === "_" && value.startsWith("__vitest_") && /__vitest_\d+__/.test(value)) return ""; | ||
| let printed = printer(value, config, indentationNext, depth, refs); | ||
| if (typeof value !== "string") { | ||
| if (printed.includes("\n")) printed = config.spacingOuter + indentationNext + printed + config.spacingOuter + indentation; | ||
| printed = `{${printed}}`; | ||
| } | ||
| return `${config.spacingInner + indentation + colors.prop.open + key + colors.prop.close}=${colors.value.open}${printed}${colors.value.close}`; | ||
| }).join(""); | ||
| } | ||
| // Return empty string if children is empty. | ||
| function printChildren(children, config, indentation, depth, refs, printer) { | ||
| return children.map((child) => config.spacingOuter + indentation + (typeof child === "string" ? printText(child, config) : printer(child, config, indentation, depth, refs))).join(""); | ||
| } | ||
| function printShadowRoot(children, config, indentation, depth, refs, printer) { | ||
| if (config.printShadowRoot === false) return ""; | ||
| return [`${config.spacingOuter + indentation}#shadow-root`, printChildren(children, config, indentation + config.indent, depth, refs, printer)].join(""); | ||
| } | ||
| function printText(text, config) { | ||
| const contentColor = config.colors.content; | ||
| return contentColor.open + escapeHTML(text) + contentColor.close; | ||
| } | ||
| function printComment(comment, config) { | ||
| const commentColor = config.colors.comment; | ||
| return `${commentColor.open}<!--${escapeHTML(comment)}-->${commentColor.close}`; | ||
| } | ||
| // Separate the functions to format props, children, and element, | ||
| // so a plugin could override a particular function, if needed. | ||
| // Too bad, so sad: the traditional (but unnecessary) space | ||
| // in a self-closing tagColor requires a second test of printedProps. | ||
| function printElement(type, printedProps, printedChildren, config, indentation) { | ||
| const tagColor = config.colors.tag; | ||
| return `${tagColor.open}<${type}${printedProps && tagColor.close + printedProps + config.spacingOuter + indentation + tagColor.open}${printedChildren ? `>${tagColor.close}${printedChildren}${config.spacingOuter}${indentation}${tagColor.open}</${type}` : `${printedProps && !config.min ? "" : " "}/`}>${tagColor.close}`; | ||
| } | ||
| function printElementAsLeaf(type, config) { | ||
| const tagColor = config.colors.tag; | ||
| return `${tagColor.open}<${type}${tagColor.close} …${tagColor.open} />${tagColor.close}`; | ||
| } | ||
| const ELEMENT_NODE = 1; | ||
| const TEXT_NODE = 3; | ||
| const COMMENT_NODE = 8; | ||
| const FRAGMENT_NODE = 11; | ||
| const ELEMENT_REGEXP = /^(?:(?:HTML|SVG)\w*)?Element$/; | ||
| function testHasAttribute(val) { | ||
| try { | ||
| return typeof val.hasAttribute === "function" && val.hasAttribute("is"); | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| function testNode(val) { | ||
| const constructorName = val.constructor.name; | ||
| const { nodeType, tagName } = val; | ||
| const isCustomElement = typeof tagName === "string" && tagName.includes("-") || testHasAttribute(val); | ||
| return nodeType === ELEMENT_NODE && (ELEMENT_REGEXP.test(constructorName) || isCustomElement) || nodeType === TEXT_NODE && constructorName === "Text" || nodeType === COMMENT_NODE && constructorName === "Comment" || nodeType === FRAGMENT_NODE && constructorName === "DocumentFragment"; | ||
| } | ||
| const test$3 = (val) => val?.constructor?.name && testNode(val); | ||
| function nodeIsText(node) { | ||
| return node.nodeType === TEXT_NODE; | ||
| } | ||
| function nodeIsComment(node) { | ||
| return node.nodeType === COMMENT_NODE; | ||
| } | ||
| function nodeIsFragment(node) { | ||
| return node.nodeType === FRAGMENT_NODE; | ||
| } | ||
| function filterChildren(children, filterNode) { | ||
| // Filter out text nodes that only contain whitespace to prevent empty lines | ||
| // This is done regardless of whether a filterNode is provided | ||
| let filtered = children.filter((node) => { | ||
| // Filter out text nodes that are only whitespace | ||
| if (node.nodeType === TEXT_NODE) | ||
| // Keep text nodes that have non-whitespace content | ||
| return (node.data || "").trim().length > 0; | ||
| return true; | ||
| }); | ||
| // Apply additional user-provided filter if specified | ||
| if (filterNode) filtered = filtered.filter(filterNode); | ||
| return filtered; | ||
| } | ||
| function serializeDOM(node, config, indentation, depth, refs, printer, filterNode) { | ||
| if (nodeIsText(node)) return printText(node.data, config); | ||
| if (nodeIsComment(node)) return printComment(node.data, config); | ||
| const type = nodeIsFragment(node) ? "DocumentFragment" : node.tagName.toLowerCase(); | ||
| if (++depth > config.maxDepth) return printElementAsLeaf(type, config); | ||
| const children = Array.prototype.slice.call(node.childNodes || node.children); | ||
| const shadowChildren = nodeIsFragment(node) || !node.shadowRoot ? [] : Array.prototype.slice.call(node.shadowRoot.children); | ||
| const resolvedChildren = filterNode ? filterChildren(children, filterNode) : children; | ||
| const resolvedShadowChildren = filterNode ? filterChildren(shadowChildren, filterNode) : shadowChildren; | ||
| return printElement(type, printProps(nodeIsFragment(node) ? [] : Array.from(node.attributes, (attr) => attr.name).sort(), nodeIsFragment(node) ? {} : [...node.attributes].reduce((props, attribute) => { | ||
| props[attribute.name] = attribute.value; | ||
| return props; | ||
| }, {}), config, indentation + config.indent, depth, refs, printer), (resolvedShadowChildren.length > 0 ? printShadowRoot(resolvedShadowChildren, config, indentation + config.indent, depth, refs, printer) : "") + printChildren(resolvedChildren, config, indentation + config.indent, depth, refs, printer), config, indentation); | ||
| } | ||
| const serialize$3 = (node, config, indentation, depth, refs, printer) => serializeDOM(node, config, indentation, depth, refs, printer); | ||
| function createDOMElementFilter(filterNode) { | ||
| return { | ||
| test: test$3, | ||
| serialize: (node, config, indentation, depth, refs, printer) => serializeDOM(node, config, indentation, depth, refs, printer, filterNode) | ||
| }; | ||
| } | ||
| const plugin$3 = { | ||
| serialize: serialize$3, | ||
| test: test$3 | ||
| }; | ||
| // SENTINEL constants are from https://github.com/immutable-js/immutable-js | ||
| const IS_ITERABLE_SENTINEL = "@@__IMMUTABLE_ITERABLE__@@"; | ||
| const IS_LIST_SENTINEL = "@@__IMMUTABLE_LIST__@@"; | ||
| const IS_KEYED_SENTINEL = "@@__IMMUTABLE_KEYED__@@"; | ||
| const IS_MAP_SENTINEL = "@@__IMMUTABLE_MAP__@@"; | ||
| const IS_ORDERED_SENTINEL = "@@__IMMUTABLE_ORDERED__@@"; | ||
| const IS_RECORD_SENTINEL = "@@__IMMUTABLE_RECORD__@@"; | ||
| const IS_SEQ_SENTINEL = "@@__IMMUTABLE_SEQ__@@"; | ||
| const IS_SET_SENTINEL = "@@__IMMUTABLE_SET__@@"; | ||
| const IS_STACK_SENTINEL = "@@__IMMUTABLE_STACK__@@"; | ||
| const getImmutableName = (name) => `Immutable.${name}`; | ||
| const printAsLeaf = (name) => `[${name}]`; | ||
| const SPACE = " "; | ||
| const LAZY = "…"; | ||
| function printImmutableEntries(val, config, indentation, depth, refs, printer, type) { | ||
| return ++depth > config.maxDepth ? printAsLeaf(getImmutableName(type)) : `${getImmutableName(type) + SPACE}{${printIteratorEntries(val.entries(), config, indentation, depth, refs, printer)}}`; | ||
| } | ||
| // Record has an entries method because it is a collection in immutable v3. | ||
| // Return an iterator for Immutable Record from version v3 or v4. | ||
| function getRecordEntries(val) { | ||
| let i = 0; | ||
| return { next() { | ||
| if (i < val._keys.length) { | ||
| const key = val._keys[i++]; | ||
| return { | ||
| done: false, | ||
| value: [key, val.get(key)] | ||
| }; | ||
| } | ||
| return { | ||
| done: true, | ||
| value: void 0 | ||
| }; | ||
| } }; | ||
| } | ||
| function printImmutableRecord(val, config, indentation, depth, refs, printer) { | ||
| // _name property is defined only for an Immutable Record instance | ||
| // which was constructed with a second optional descriptive name arg | ||
| const name = getImmutableName(val._name || "Record"); | ||
| return ++depth > config.maxDepth ? printAsLeaf(name) : `${name + SPACE}{${printIteratorEntries(getRecordEntries(val), config, indentation, depth, refs, printer)}}`; | ||
| } | ||
| function printImmutableSeq(val, config, indentation, depth, refs, printer) { | ||
| const name = getImmutableName("Seq"); | ||
| if (++depth > config.maxDepth) return printAsLeaf(name); | ||
| if (val[IS_KEYED_SENTINEL]) return `${name + SPACE}{${val._iter || val._object ? printIteratorEntries(val.entries(), config, indentation, depth, refs, printer) : LAZY}}`; | ||
| return `${name + SPACE}[${val._iter || val._array || val._collection || val._iterable ? printIteratorValues(val.values(), config, indentation, depth, refs, printer) : LAZY}]`; | ||
| } | ||
| function printImmutableValues(val, config, indentation, depth, refs, printer, type) { | ||
| return ++depth > config.maxDepth ? printAsLeaf(getImmutableName(type)) : `${getImmutableName(type) + SPACE}[${printIteratorValues(val.values(), config, indentation, depth, refs, printer)}]`; | ||
| } | ||
| const serialize$2 = (val, config, indentation, depth, refs, printer) => { | ||
| if (val[IS_MAP_SENTINEL]) return printImmutableEntries(val, config, indentation, depth, refs, printer, val[IS_ORDERED_SENTINEL] ? "OrderedMap" : "Map"); | ||
| if (val[IS_LIST_SENTINEL]) return printImmutableValues(val, config, indentation, depth, refs, printer, "List"); | ||
| if (val[IS_SET_SENTINEL]) return printImmutableValues(val, config, indentation, depth, refs, printer, val[IS_ORDERED_SENTINEL] ? "OrderedSet" : "Set"); | ||
| if (val[IS_STACK_SENTINEL]) return printImmutableValues(val, config, indentation, depth, refs, printer, "Stack"); | ||
| if (val[IS_SEQ_SENTINEL]) return printImmutableSeq(val, config, indentation, depth, refs, printer); | ||
| // For compatibility with immutable v3 and v4, let record be the default. | ||
| return printImmutableRecord(val, config, indentation, depth, refs, printer); | ||
| }; | ||
| // Explicitly comparing sentinel properties to true avoids false positive | ||
| // when mock identity-obj-proxy returns the key as the value for any key. | ||
| const test$2 = (val) => val && (val[IS_ITERABLE_SENTINEL] === true || val[IS_RECORD_SENTINEL] === true); | ||
| const plugin$2 = { | ||
| serialize: serialize$2, | ||
| test: test$2 | ||
| }; | ||
| function getDefaultExportFromCjs(x) { | ||
| return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; | ||
| } | ||
| var reactIs$1 = { exports: {} }; | ||
| var reactIs_production = {}; | ||
| /** | ||
| * @license React | ||
| * react-is.production.js | ||
| * | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
| var hasRequiredReactIs_production; | ||
| function requireReactIs_production() { | ||
| if (hasRequiredReactIs_production) return reactIs_production; | ||
| hasRequiredReactIs_production = 1; | ||
| var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_VIEW_TRANSITION_TYPE = Symbol.for("react.view_transition"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"); | ||
| function typeOf(object) { | ||
| if ("object" === typeof object && null !== object) { | ||
| var $$typeof = object.$$typeof; | ||
| switch ($$typeof) { | ||
| case REACT_ELEMENT_TYPE: switch (object = object.type, object) { | ||
| case REACT_FRAGMENT_TYPE: | ||
| case REACT_PROFILER_TYPE: | ||
| case REACT_STRICT_MODE_TYPE: | ||
| case REACT_SUSPENSE_TYPE: | ||
| case REACT_SUSPENSE_LIST_TYPE: | ||
| case REACT_VIEW_TRANSITION_TYPE: return object; | ||
| default: switch (object = object && object.$$typeof, object) { | ||
| case REACT_CONTEXT_TYPE: | ||
| case REACT_FORWARD_REF_TYPE: | ||
| case REACT_LAZY_TYPE: | ||
| case REACT_MEMO_TYPE: return object; | ||
| case REACT_CONSUMER_TYPE: return object; | ||
| default: return $$typeof; | ||
| } | ||
| } | ||
| case REACT_PORTAL_TYPE: return $$typeof; | ||
| } | ||
| } | ||
| } | ||
| reactIs_production.ContextConsumer = REACT_CONSUMER_TYPE; | ||
| reactIs_production.ContextProvider = REACT_CONTEXT_TYPE; | ||
| reactIs_production.Element = REACT_ELEMENT_TYPE; | ||
| reactIs_production.ForwardRef = REACT_FORWARD_REF_TYPE; | ||
| reactIs_production.Fragment = REACT_FRAGMENT_TYPE; | ||
| reactIs_production.Lazy = REACT_LAZY_TYPE; | ||
| reactIs_production.Memo = REACT_MEMO_TYPE; | ||
| reactIs_production.Portal = REACT_PORTAL_TYPE; | ||
| reactIs_production.Profiler = REACT_PROFILER_TYPE; | ||
| reactIs_production.StrictMode = REACT_STRICT_MODE_TYPE; | ||
| reactIs_production.Suspense = REACT_SUSPENSE_TYPE; | ||
| reactIs_production.SuspenseList = REACT_SUSPENSE_LIST_TYPE; | ||
| reactIs_production.isContextConsumer = function(object) { | ||
| return typeOf(object) === REACT_CONSUMER_TYPE; | ||
| }; | ||
| reactIs_production.isContextProvider = function(object) { | ||
| return typeOf(object) === REACT_CONTEXT_TYPE; | ||
| }; | ||
| reactIs_production.isElement = function(object) { | ||
| return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE; | ||
| }; | ||
| reactIs_production.isForwardRef = function(object) { | ||
| return typeOf(object) === REACT_FORWARD_REF_TYPE; | ||
| }; | ||
| reactIs_production.isFragment = function(object) { | ||
| return typeOf(object) === REACT_FRAGMENT_TYPE; | ||
| }; | ||
| reactIs_production.isLazy = function(object) { | ||
| return typeOf(object) === REACT_LAZY_TYPE; | ||
| }; | ||
| reactIs_production.isMemo = function(object) { | ||
| return typeOf(object) === REACT_MEMO_TYPE; | ||
| }; | ||
| reactIs_production.isPortal = function(object) { | ||
| return typeOf(object) === REACT_PORTAL_TYPE; | ||
| }; | ||
| reactIs_production.isProfiler = function(object) { | ||
| return typeOf(object) === REACT_PROFILER_TYPE; | ||
| }; | ||
| reactIs_production.isStrictMode = function(object) { | ||
| return typeOf(object) === REACT_STRICT_MODE_TYPE; | ||
| }; | ||
| reactIs_production.isSuspense = function(object) { | ||
| return typeOf(object) === REACT_SUSPENSE_TYPE; | ||
| }; | ||
| reactIs_production.isSuspenseList = function(object) { | ||
| return typeOf(object) === REACT_SUSPENSE_LIST_TYPE; | ||
| }; | ||
| reactIs_production.isValidElementType = function(type) { | ||
| return "string" === typeof type || "function" === typeof type || type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || "object" === typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_CONSUMER_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_CLIENT_REFERENCE || void 0 !== type.getModuleId) ? true : false; | ||
| }; | ||
| reactIs_production.typeOf = typeOf; | ||
| return reactIs_production; | ||
| } | ||
| var hasRequiredReactIs$1; | ||
| function requireReactIs$1() { | ||
| if (hasRequiredReactIs$1) return reactIs$1.exports; | ||
| hasRequiredReactIs$1 = 1; | ||
| reactIs$1.exports = requireReactIs_production(); | ||
| return reactIs$1.exports; | ||
| } | ||
| var reactIsExports$1 = requireReactIs$1(); | ||
| var ReactIs19 = /* @__PURE__ */ _mergeNamespaces$1({ | ||
| __proto__: null, | ||
| default: /* @__PURE__ */ getDefaultExportFromCjs(reactIsExports$1) | ||
| }, [reactIsExports$1]); | ||
| var reactIs = { exports: {} }; | ||
| var reactIs_production_min = {}; | ||
| /** | ||
| * @license React | ||
| * react-is.production.min.js | ||
| * | ||
| * Copyright (c) Facebook, Inc. and its affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| */ | ||
| var hasRequiredReactIs_production_min; | ||
| function requireReactIs_production_min() { | ||
| if (hasRequiredReactIs_production_min) return reactIs_production_min; | ||
| hasRequiredReactIs_production_min = 1; | ||
| var b = Symbol.for("react.element"), c = Symbol.for("react.portal"), d = Symbol.for("react.fragment"), e = Symbol.for("react.strict_mode"), f = Symbol.for("react.profiler"), g = Symbol.for("react.provider"), h = Symbol.for("react.context"), k = Symbol.for("react.server_context"), l = Symbol.for("react.forward_ref"), m = Symbol.for("react.suspense"), n = Symbol.for("react.suspense_list"), p = Symbol.for("react.memo"), q = Symbol.for("react.lazy"), t = Symbol.for("react.offscreen"), u = Symbol.for("react.module.reference"); | ||
| function v(a) { | ||
| if ("object" === typeof a && null !== a) { | ||
| var r = a.$$typeof; | ||
| switch (r) { | ||
| case b: switch (a = a.type, a) { | ||
| case d: | ||
| case f: | ||
| case e: | ||
| case m: | ||
| case n: return a; | ||
| default: switch (a = a && a.$$typeof, a) { | ||
| case k: | ||
| case h: | ||
| case l: | ||
| case q: | ||
| case p: | ||
| case g: return a; | ||
| default: return r; | ||
| } | ||
| } | ||
| case c: return r; | ||
| } | ||
| } | ||
| } | ||
| reactIs_production_min.ContextConsumer = h; | ||
| reactIs_production_min.ContextProvider = g; | ||
| reactIs_production_min.Element = b; | ||
| reactIs_production_min.ForwardRef = l; | ||
| reactIs_production_min.Fragment = d; | ||
| reactIs_production_min.Lazy = q; | ||
| reactIs_production_min.Memo = p; | ||
| reactIs_production_min.Portal = c; | ||
| reactIs_production_min.Profiler = f; | ||
| reactIs_production_min.StrictMode = e; | ||
| reactIs_production_min.Suspense = m; | ||
| reactIs_production_min.SuspenseList = n; | ||
| reactIs_production_min.isAsyncMode = function() { | ||
| return false; | ||
| }; | ||
| reactIs_production_min.isConcurrentMode = function() { | ||
| return false; | ||
| }; | ||
| reactIs_production_min.isContextConsumer = function(a) { | ||
| return v(a) === h; | ||
| }; | ||
| reactIs_production_min.isContextProvider = function(a) { | ||
| return v(a) === g; | ||
| }; | ||
| reactIs_production_min.isElement = function(a) { | ||
| return "object" === typeof a && null !== a && a.$$typeof === b; | ||
| }; | ||
| reactIs_production_min.isForwardRef = function(a) { | ||
| return v(a) === l; | ||
| }; | ||
| reactIs_production_min.isFragment = function(a) { | ||
| return v(a) === d; | ||
| }; | ||
| reactIs_production_min.isLazy = function(a) { | ||
| return v(a) === q; | ||
| }; | ||
| reactIs_production_min.isMemo = function(a) { | ||
| return v(a) === p; | ||
| }; | ||
| reactIs_production_min.isPortal = function(a) { | ||
| return v(a) === c; | ||
| }; | ||
| reactIs_production_min.isProfiler = function(a) { | ||
| return v(a) === f; | ||
| }; | ||
| reactIs_production_min.isStrictMode = function(a) { | ||
| return v(a) === e; | ||
| }; | ||
| reactIs_production_min.isSuspense = function(a) { | ||
| return v(a) === m; | ||
| }; | ||
| reactIs_production_min.isSuspenseList = function(a) { | ||
| return v(a) === n; | ||
| }; | ||
| reactIs_production_min.isValidElementType = function(a) { | ||
| return "string" === typeof a || "function" === typeof a || a === d || a === f || a === e || a === m || a === n || a === t || "object" === typeof a && null !== a && (a.$$typeof === q || a.$$typeof === p || a.$$typeof === g || a.$$typeof === h || a.$$typeof === l || a.$$typeof === u || void 0 !== a.getModuleId) ? true : false; | ||
| }; | ||
| reactIs_production_min.typeOf = v; | ||
| return reactIs_production_min; | ||
| } | ||
| var hasRequiredReactIs; | ||
| function requireReactIs() { | ||
| if (hasRequiredReactIs) return reactIs.exports; | ||
| hasRequiredReactIs = 1; | ||
| reactIs.exports = requireReactIs_production_min(); | ||
| return reactIs.exports; | ||
| } | ||
| var reactIsExports = requireReactIs(); | ||
| var ReactIs18 = /* @__PURE__ */ _mergeNamespaces$1({ | ||
| __proto__: null, | ||
| default: /* @__PURE__ */ getDefaultExportFromCjs(reactIsExports) | ||
| }, [reactIsExports]); | ||
| const ReactIs = Object.fromEntries([ | ||
| "isAsyncMode", | ||
| "isConcurrentMode", | ||
| "isContextConsumer", | ||
| "isContextProvider", | ||
| "isElement", | ||
| "isForwardRef", | ||
| "isFragment", | ||
| "isLazy", | ||
| "isMemo", | ||
| "isPortal", | ||
| "isProfiler", | ||
| "isStrictMode", | ||
| "isSuspense", | ||
| "isSuspenseList", | ||
| "isValidElementType" | ||
| ].map((m) => [m, (v) => ReactIs18[m](v) || ReactIs19[m](v)])); | ||
| // Given element.props.children, or subtree during recursive traversal, | ||
| // return flattened array of children. | ||
| function getChildren(arg, children = []) { | ||
| if (Array.isArray(arg)) for (const item of arg) getChildren(item, children); | ||
| else if (arg != null && arg !== false && arg !== "") children.push(arg); | ||
| return children; | ||
| } | ||
| function getType(element) { | ||
| const type = element.type; | ||
| if (typeof type === "string") return type; | ||
| if (typeof type === "function") return type.displayName || type.name || "Unknown"; | ||
| if (ReactIs.isFragment(element)) return "React.Fragment"; | ||
| if (ReactIs.isSuspense(element)) return "React.Suspense"; | ||
| if (typeof type === "object" && type !== null) { | ||
| if (ReactIs.isContextProvider(element)) return "Context.Provider"; | ||
| if (ReactIs.isContextConsumer(element)) return "Context.Consumer"; | ||
| if (ReactIs.isForwardRef(element)) { | ||
| if (type.displayName) return type.displayName; | ||
| const functionName = type.render.displayName || type.render.name || ""; | ||
| return functionName === "" ? "ForwardRef" : `ForwardRef(${functionName})`; | ||
| } | ||
| if (ReactIs.isMemo(element)) { | ||
| const functionName = type.displayName || type.type.displayName || type.type.name || ""; | ||
| return functionName === "" ? "Memo" : `Memo(${functionName})`; | ||
| } | ||
| } | ||
| return "UNDEFINED"; | ||
| } | ||
| function getPropKeys$1(element) { | ||
| const { props } = element; | ||
| return Object.keys(props).filter((key) => key !== "children" && props[key] !== void 0).sort(); | ||
| } | ||
| const serialize$1 = (element, config, indentation, depth, refs, printer) => ++depth > config.maxDepth ? printElementAsLeaf(getType(element), config) : printElement(getType(element), printProps(getPropKeys$1(element), element.props, config, indentation + config.indent, depth, refs, printer), printChildren(getChildren(element.props.children), config, indentation + config.indent, depth, refs, printer), config, indentation); | ||
| const test$1 = (val) => val != null && ReactIs.isElement(val); | ||
| const plugin$1 = { | ||
| serialize: serialize$1, | ||
| test: test$1 | ||
| }; | ||
| const testSymbol = typeof Symbol === "function" && Symbol.for ? Symbol.for("react.test.json") : 245830487; | ||
| function getPropKeys(object) { | ||
| const { props } = object; | ||
| return props ? Object.keys(props).filter((key) => props[key] !== void 0).sort() : []; | ||
| } | ||
| const serialize = (object, config, indentation, depth, refs, printer) => ++depth > config.maxDepth ? printElementAsLeaf(object.type, config) : printElement(object.type, object.props ? printProps(getPropKeys(object), object.props, config, indentation + config.indent, depth, refs, printer) : "", object.children ? printChildren(object.children, config, indentation + config.indent, depth, refs, printer) : "", config, indentation); | ||
| const test = (val) => val && val.$$typeof === testSymbol; | ||
| const plugin = { | ||
| serialize, | ||
| test | ||
| }; | ||
| const toString = Object.prototype.toString; | ||
| const toISOString = Date.prototype.toISOString; | ||
| const errorToString = Error.prototype.toString; | ||
| const regExpToString = RegExp.prototype.toString; | ||
| /** | ||
| * Explicitly comparing typeof constructor to function avoids undefined as name | ||
| * when mock identity-obj-proxy returns the key as the value for any key. | ||
| */ | ||
| function getConstructorName(val) { | ||
| return typeof val.constructor === "function" && val.constructor.name || "Object"; | ||
| } | ||
| /** Is val is equal to global window object? Works even if it does not exist :) */ | ||
| function isWindow(val) { | ||
| return typeof window !== "undefined" && val === window; | ||
| } | ||
| // eslint-disable-next-line regexp/no-super-linear-backtracking | ||
| const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/; | ||
| const NEWLINE_REGEXP = /\n/g; | ||
| class PrettyFormatPluginError extends Error { | ||
| constructor(message, stack) { | ||
| super(message); | ||
| this.stack = stack; | ||
| this.name = this.constructor.name; | ||
| } | ||
| } | ||
| function isToStringedArrayType(toStringed) { | ||
| return toStringed === "[object Array]" || toStringed === "[object ArrayBuffer]" || toStringed === "[object DataView]" || toStringed === "[object Float32Array]" || toStringed === "[object Float64Array]" || toStringed === "[object Int8Array]" || toStringed === "[object Int16Array]" || toStringed === "[object Int32Array]" || toStringed === "[object Uint8Array]" || toStringed === "[object Uint8ClampedArray]" || toStringed === "[object Uint16Array]" || toStringed === "[object Uint32Array]"; | ||
| } | ||
| function printNumber(val) { | ||
| return Object.is(val, -0) ? "-0" : String(val); | ||
| } | ||
| function printBigInt(val) { | ||
| return String(`${val}n`); | ||
| } | ||
| function printFunction(val, printFunctionName) { | ||
| if (!printFunctionName) return "[Function]"; | ||
| return `[Function ${val.name || "anonymous"}]`; | ||
| } | ||
| function printSymbol(val) { | ||
| return String(val).replace(SYMBOL_REGEXP, "Symbol($1)"); | ||
| } | ||
| function printError(val) { | ||
| return `[${errorToString.call(val)}]`; | ||
| } | ||
| /** | ||
| * The first port of call for printing an object, handles most of the | ||
| * data-types in JS. | ||
| */ | ||
| function printBasicValue(val, printFunctionName, escapeRegex, escapeString, singleQuote) { | ||
| if (val === true || val === false) return `${val}`; | ||
| if (val === void 0) return "undefined"; | ||
| if (val === null) return "null"; | ||
| const typeOf = typeof val; | ||
| if (typeOf === "number") return printNumber(val); | ||
| if (typeOf === "bigint") return printBigInt(val); | ||
| if (typeOf === "string") { | ||
| const q = singleQuote ? "'" : "\""; | ||
| if (escapeString) { | ||
| // escape quote in each case, e.g. | ||
| // it's me -> 'it\'s me' | ||
| // say "hi" -> "say \"hi\"" | ||
| const escapePattern = singleQuote ? /['\\]/g : /["\\]/g; | ||
| return `${q}${val.replaceAll(escapePattern, "\\$&")}${q}`; | ||
| } | ||
| return `${q}${val}${q}`; | ||
| } | ||
| if (typeOf === "function") return printFunction(val, printFunctionName); | ||
| if (typeOf === "symbol") return printSymbol(val); | ||
| const toStringed = toString.call(val); | ||
| if (toStringed === "[object WeakMap]") return "WeakMap {}"; | ||
| if (toStringed === "[object WeakSet]") return "WeakSet {}"; | ||
| if (toStringed === "[object Function]" || toStringed === "[object GeneratorFunction]") return printFunction(val, printFunctionName); | ||
| if (toStringed === "[object Symbol]") return printSymbol(val); | ||
| if (toStringed === "[object Date]") return Number.isNaN(+val) ? "Date { NaN }" : toISOString.call(val); | ||
| if (toStringed === "[object Error]") return printError(val); | ||
| if (toStringed === "[object RegExp]") { | ||
| if (escapeRegex) | ||
| // https://github.com/benjamingr/RegExp.escape/blob/main/polyfill.js | ||
| return regExpToString.call(val).replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&"); | ||
| return regExpToString.call(val); | ||
| } | ||
| if (val instanceof Error) return printError(val); | ||
| return null; | ||
| } | ||
| /** | ||
| * Handles more complex objects ( such as objects with circular references. | ||
| * maps and sets etc ) | ||
| */ | ||
| function printComplexValue(val, config, indentation, depth, refs, hasCalledToJSON) { | ||
| if (refs.includes(val)) return "[Circular]"; | ||
| refs = [...refs]; | ||
| refs.push(val); | ||
| const hitMaxDepth = ++depth > config.maxDepth; | ||
| const min = config.min; | ||
| if (config.callToJSON && !hitMaxDepth && val.toJSON && typeof val.toJSON === "function" && !hasCalledToJSON) return printer(val.toJSON(), config, indentation, depth, refs, true); | ||
| const toStringed = toString.call(val); | ||
| if (toStringed === "[object Arguments]") return hitMaxDepth ? "[Arguments]" : `${min ? "" : "Arguments "}[${printListItems(val, config, indentation, depth, refs, printer)}]`; | ||
| if (isToStringedArrayType(toStringed)) return hitMaxDepth ? `[${val.constructor.name}]` : `${!config.printBasicPrototype && val.constructor.name === "Array" ? "" : `${val.constructor.name} `}[${printListItems(val, config, indentation, depth, refs, printer)}]`; | ||
| if (toStringed === "[object Map]") return hitMaxDepth ? "[Map]" : `Map {${printIteratorEntries(val.entries(), config, indentation, depth, refs, printer, " => ", val.size)}}`; | ||
| if (toStringed === "[object Set]") return hitMaxDepth ? "[Set]" : `Set {${printIteratorValues(val.values(), config, indentation, depth, refs, printer, val.size)}}`; | ||
| // Avoid failure to serialize global window object in jsdom test environment. | ||
| // For example, not even relevant if window is prop of React element. | ||
| return hitMaxDepth || isWindow(val) ? `[${getConstructorName(val)}]` : `${!config.printBasicPrototype && getConstructorName(val) === "Object" ? "" : `${getConstructorName(val)} `}{${printObjectProperties(val, config, indentation, depth, refs, printer)}}`; | ||
| } | ||
| const ErrorPlugin = { | ||
| test: (val) => val && val instanceof Error, | ||
| serialize(val, config, indentation, depth, refs, printer) { | ||
| if (refs.includes(val)) return "[Circular]"; | ||
| refs = [...refs, val]; | ||
| const hitMaxDepth = ++depth > config.maxDepth; | ||
| const { message, cause, ...rest } = val; | ||
| const entries = { | ||
| message, | ||
| ...typeof cause !== "undefined" ? { cause } : {}, | ||
| ...val instanceof AggregateError ? { errors: val.errors } : {}, | ||
| ...rest | ||
| }; | ||
| const name = val.name !== "Error" ? val.name : getConstructorName(val); | ||
| return hitMaxDepth ? `[${name}]` : `${name} {${printObjectProperties(entries, config, indentation, depth, refs, printer, null)}}`; | ||
| } | ||
| }; | ||
| function isNewPlugin(plugin) { | ||
| return plugin.serialize != null; | ||
| } | ||
| function printPlugin(plugin, val, config, indentation, depth, refs) { | ||
| let printed; | ||
| try { | ||
| printed = isNewPlugin(plugin) ? plugin.serialize(val, config, indentation, depth, refs, printer) : plugin.print(val, (valChild) => printer(valChild, config, indentation, depth, refs), (str) => { | ||
| const indentationNext = indentation + config.indent; | ||
| return indentationNext + str.replaceAll(NEWLINE_REGEXP, `\n${indentationNext}`); | ||
| }, { | ||
| edgeSpacing: config.spacingOuter, | ||
| min: config.min, | ||
| spacing: config.spacingInner | ||
| }, config.colors); | ||
| } catch (error) { | ||
| throw new PrettyFormatPluginError(error.message, error.stack); | ||
| } | ||
| if (typeof printed !== "string") throw new TypeError(`pretty-format: Plugin must return type "string" but instead returned "${typeof printed}".`); | ||
| return printed; | ||
| } | ||
| function findPlugin(plugins, val) { | ||
| for (const plugin of plugins) try { | ||
| if (plugin.test(val)) return plugin; | ||
| } catch (error) { | ||
| throw new PrettyFormatPluginError(error.message, error.stack); | ||
| } | ||
| return null; | ||
| } | ||
| function printer(val, config, indentation, depth, refs, hasCalledToJSON) { | ||
| let result; | ||
| const plugin = findPlugin(config.plugins, val); | ||
| if (plugin !== null) result = printPlugin(plugin, val, config, indentation, depth, refs); | ||
| else { | ||
| const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString, config.singleQuote); | ||
| if (basicResult !== null) result = basicResult; | ||
| else result = printComplexValue(val, config, indentation, depth, refs, hasCalledToJSON); | ||
| } | ||
| // Per-depth output budget (inspired by Node's util.inspect). | ||
| // Each depth level tracks output independently, so nested results | ||
| // don't inflate a single counter (which would undercount by ~Nx for | ||
| // N levels of nesting). Nodes at the same depth produce disjoint spans | ||
| // in the output string, so each bucket accurately reflects output at | ||
| // that level. Total output is bounded by maxDepth × maxOutputLength. | ||
| config._outputLengthPerDepth[depth] ??= 0; | ||
| config._outputLengthPerDepth[depth] += result.length; | ||
| if (config._outputLengthPerDepth[depth] > config.maxOutputLength) config.maxDepth = 0; | ||
| return result; | ||
| } | ||
| const DEFAULT_THEME = { | ||
| comment: "gray", | ||
| content: "reset", | ||
| prop: "yellow", | ||
| tag: "cyan", | ||
| value: "green" | ||
| }; | ||
| const DEFAULT_THEME_KEYS = Object.keys(DEFAULT_THEME); | ||
| const DEFAULT_OPTIONS = { | ||
| callToJSON: true, | ||
| compareKeys: void 0, | ||
| escapeRegex: false, | ||
| escapeString: true, | ||
| highlight: false, | ||
| indent: 2, | ||
| maxDepth: Number.POSITIVE_INFINITY, | ||
| maxOutputLength: 1e6, | ||
| maxWidth: Number.POSITIVE_INFINITY, | ||
| min: false, | ||
| plugins: [], | ||
| printBasicPrototype: true, | ||
| printFunctionName: true, | ||
| printShadowRoot: true, | ||
| theme: DEFAULT_THEME, | ||
| singleQuote: false, | ||
| quoteKeys: true, | ||
| spacingInner: "\n", | ||
| spacingOuter: "\n" | ||
| }; | ||
| function validateOptions(options) { | ||
| for (const key of Object.keys(options)) if (!Object.hasOwn(DEFAULT_OPTIONS, key)) throw new Error(`pretty-format: Unknown option "${key}".`); | ||
| if (options.min && options.indent !== void 0 && options.indent !== 0) throw new Error("pretty-format: Options \"min\" and \"indent\" cannot be used together."); | ||
| } | ||
| function getColorsHighlight() { | ||
| return DEFAULT_THEME_KEYS.reduce((colors, key) => { | ||
| const value = DEFAULT_THEME[key]; | ||
| const color = value && y[value]; | ||
| if (color && typeof color.close === "string" && typeof color.open === "string") colors[key] = color; | ||
| else throw new Error(`pretty-format: Option "theme" has a key "${key}" whose value "${value}" is undefined in ansi-styles.`); | ||
| return colors; | ||
| }, Object.create(null)); | ||
| } | ||
| function getColorsEmpty() { | ||
| return DEFAULT_THEME_KEYS.reduce((colors, key) => { | ||
| colors[key] = { | ||
| close: "", | ||
| open: "" | ||
| }; | ||
| return colors; | ||
| }, Object.create(null)); | ||
| } | ||
| function getPrintFunctionName(options) { | ||
| return options?.printFunctionName ?? DEFAULT_OPTIONS.printFunctionName; | ||
| } | ||
| function getEscapeRegex(options) { | ||
| return options?.escapeRegex ?? DEFAULT_OPTIONS.escapeRegex; | ||
| } | ||
| function getEscapeString(options) { | ||
| return options?.escapeString ?? DEFAULT_OPTIONS.escapeString; | ||
| } | ||
| function getConfig(options) { | ||
| return { | ||
| callToJSON: options?.callToJSON ?? DEFAULT_OPTIONS.callToJSON, | ||
| colors: options?.highlight ? getColorsHighlight() : getColorsEmpty(), | ||
| compareKeys: typeof options?.compareKeys === "function" || options?.compareKeys === null ? options.compareKeys : DEFAULT_OPTIONS.compareKeys, | ||
| escapeRegex: getEscapeRegex(options), | ||
| escapeString: getEscapeString(options), | ||
| indent: options?.min ? "" : createIndent(options?.indent ?? DEFAULT_OPTIONS.indent), | ||
| maxDepth: options?.maxDepth ?? DEFAULT_OPTIONS.maxDepth, | ||
| maxWidth: options?.maxWidth ?? DEFAULT_OPTIONS.maxWidth, | ||
| min: options?.min ?? DEFAULT_OPTIONS.min, | ||
| plugins: options?.plugins ?? DEFAULT_OPTIONS.plugins, | ||
| printBasicPrototype: options?.printBasicPrototype ?? !options?.min, | ||
| printFunctionName: getPrintFunctionName(options), | ||
| printShadowRoot: options?.printShadowRoot ?? true, | ||
| spacingInner: options?.spacingInner ?? (options?.min ? " " : "\n"), | ||
| spacingOuter: options?.spacingOuter ?? (options?.min ? "" : "\n"), | ||
| singleQuote: options?.singleQuote ?? DEFAULT_OPTIONS.singleQuote, | ||
| quoteKeys: options?.quoteKeys ?? DEFAULT_OPTIONS.quoteKeys, | ||
| maxOutputLength: options?.maxOutputLength ?? DEFAULT_OPTIONS.maxOutputLength, | ||
| _outputLengthPerDepth: [] | ||
| }; | ||
| } | ||
| function createIndent(indent) { | ||
| return Array.from({ length: indent + 1 }).join(" "); | ||
| } | ||
| /** | ||
| * Returns a presentation string of your `val` object | ||
| * @param val any potential JavaScript object | ||
| * @param options Custom settings | ||
| */ | ||
| function format(val, options) { | ||
| if (options) validateOptions(options); | ||
| const config = getConfig(options); | ||
| const plugin = findPlugin(config.plugins, val); | ||
| if (plugin !== null) return printPlugin(plugin, val, config, "", 0, []); | ||
| const basicResult = printBasicValue(val, config.printFunctionName, config.escapeRegex, config.escapeString, config.singleQuote); | ||
| if (basicResult !== null) return basicResult; | ||
| return printComplexValue(val, config, "", 0, []); | ||
| } | ||
| const plugins = { | ||
| AsymmetricMatcher: plugin$5, | ||
| DOMCollection: plugin$4, | ||
| DOMElement: plugin$3, | ||
| Immutable: plugin$2, | ||
| ReactElement: plugin$1, | ||
| ReactTestComponent: plugin, | ||
| Error: ErrorPlugin | ||
| }; | ||
| export { createDOMElementFilter as c, format as f, plugins as p }; |
| import * as chai from 'chai'; | ||
| import { createHook } from 'node:async_hooks'; | ||
| import { t as takeCoverageInsideWorker } from './coverage.BfSEMtie.js'; | ||
| import { r as rpc } from './rpc.iNjF664v.js'; | ||
| import { l as loadDiffConfig, a as loadSnapshotSerializers } from './setup-common.vxjAyUtK.js'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import { T as TestRunner } from './index.CLtI1k_4.js'; | ||
| function setupChaiConfig(config) { | ||
| Object.assign(chai.config, config); | ||
| } | ||
| async function resolveSnapshotEnvironment(config, moduleRunner) { | ||
| if (!config.snapshotEnvironment) { | ||
| const { VitestNodeSnapshotEnvironment } = await import('./node.BPMnm_Q2.js'); | ||
| return new VitestNodeSnapshotEnvironment(); | ||
| } | ||
| const mod = await moduleRunner.import(config.snapshotEnvironment); | ||
| if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`"); | ||
| return mod.default; | ||
| } | ||
| const IGNORED_TYPES = new Set([ | ||
| "DNSCHANNEL", | ||
| "ELDHISTOGRAM", | ||
| "PerformanceObserver", | ||
| "RANDOMBYTESREQUEST", | ||
| "SIGNREQUEST", | ||
| "STREAM_END_OF_STREAM", | ||
| "TCPWRAP", | ||
| "TIMERWRAP", | ||
| "TLSWRAP", | ||
| "ZLIB" | ||
| ]); | ||
| function detectAsyncLeaks(testFile, projectName) { | ||
| const resources = /* @__PURE__ */ new Map(); | ||
| const hook = createHook({ | ||
| init(asyncId, type, triggerAsyncId, resource) { | ||
| if (IGNORED_TYPES.has(type)) return; | ||
| let stack = ""; | ||
| const limit = Error.stackTraceLimit; | ||
| // VitestModuleEvaluator's async wrapper of node:vm causes out-of-bound stack traces, simply skip it. | ||
| // Crash fixed in https://github.com/vitejs/vite/pull/21585 | ||
| try { | ||
| Error.stackTraceLimit = 100; | ||
| stack = (/* @__PURE__ */ new Error("VITEST_DETECT_ASYNC_LEAKS")).stack || ""; | ||
| } catch { | ||
| return; | ||
| } finally { | ||
| Error.stackTraceLimit = limit; | ||
| } | ||
| if (!stack.includes(testFile)) { | ||
| const trigger = resources.get(triggerAsyncId); | ||
| if (!trigger) return; | ||
| stack = trigger.stack; | ||
| } | ||
| let isActive = isActiveDefault; | ||
| if ("hasRef" in resource) { | ||
| const ref = new WeakRef(resource); | ||
| isActive = () => ref.deref()?.hasRef() ?? false; | ||
| } | ||
| resources.set(asyncId, { | ||
| type, | ||
| stack, | ||
| projectName, | ||
| filename: testFile, | ||
| isActive | ||
| }); | ||
| }, | ||
| destroy(asyncId) { | ||
| if (resources.get(asyncId)?.type !== "PROMISE") resources.delete(asyncId); | ||
| }, | ||
| promiseResolve(asyncId) { | ||
| resources.delete(asyncId); | ||
| } | ||
| }); | ||
| hook.enable(); | ||
| return async function collect() { | ||
| await new Promise((resolve) => setImmediate(resolve)); | ||
| hook.disable(); | ||
| const leaks = []; | ||
| for (const resource of resources.values()) if (resource.isActive()) leaks.push({ | ||
| stack: resource.stack, | ||
| type: resource.type, | ||
| filename: resource.filename, | ||
| projectName: resource.projectName | ||
| }); | ||
| resources.clear(); | ||
| return leaks; | ||
| }; | ||
| } | ||
| function isActiveDefault() { | ||
| return true; | ||
| } | ||
| async function getTestRunnerConstructor(config, moduleRunner) { | ||
| if (!config.runner) return TestRunner; | ||
| const mod = await moduleRunner.import(config.runner); | ||
| if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`); | ||
| return mod.default; | ||
| } | ||
| async function resolveTestRunner(config, moduleRunner, traces) { | ||
| const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config); | ||
| // inject private executor to every runner | ||
| Object.defineProperty(testRunner, "moduleRunner", { | ||
| value: moduleRunner, | ||
| enumerable: false, | ||
| configurable: false | ||
| }); | ||
| if (!testRunner.config) testRunner.config = config; | ||
| if (!testRunner.importFile) throw new Error("Runner must implement \"importFile\" method."); | ||
| if ("__setTraces" in testRunner) testRunner.__setTraces(traces); | ||
| const [diffOptions] = await Promise.all([loadDiffConfig(config, moduleRunner), loadSnapshotSerializers(config, moduleRunner)]); | ||
| testRunner.config._diffOptions = diffOptions; | ||
| // patch some methods, so custom runners don't need to call RPC | ||
| const originalOnTaskUpdate = testRunner.onTaskUpdate; | ||
| testRunner.onTaskUpdate = async (task, events) => { | ||
| const p = rpc().onTaskUpdate(task, events); | ||
| await originalOnTaskUpdate?.call(testRunner, task, events); | ||
| return p; | ||
| }; | ||
| // patch some methods, so custom runners don't need to call RPC | ||
| const originalOnTestAnnotate = testRunner.onTestAnnotate; | ||
| testRunner.onTestAnnotate = async (test, annotation) => { | ||
| const p = rpc().onTaskArtifactRecord(test.id, { | ||
| type: "internal:annotation", | ||
| location: annotation.location, | ||
| annotation | ||
| }); | ||
| const overriddenResult = await originalOnTestAnnotate?.call(testRunner, test, annotation); | ||
| const vitestResult = await p; | ||
| return overriddenResult || vitestResult.annotation; | ||
| }; | ||
| const originalOnTestArtifactRecord = testRunner.onTestArtifactRecord; | ||
| testRunner.onTestArtifactRecord = async (test, artifact) => { | ||
| const p = rpc().onTaskArtifactRecord(test.id, artifact); | ||
| const overriddenResult = await originalOnTestArtifactRecord?.call(testRunner, test, artifact); | ||
| const vitestResult = await p; | ||
| return overriddenResult || vitestResult; | ||
| }; | ||
| const originalOnCollectStart = testRunner.onCollectStart; | ||
| testRunner.onCollectStart = async (file) => { | ||
| await rpc().onQueued(file); | ||
| await originalOnCollectStart?.call(testRunner, file); | ||
| }; | ||
| const originalOnCollected = testRunner.onCollected; | ||
| testRunner.onCollected = async (files) => { | ||
| const state = getWorkerState(); | ||
| files.forEach((file) => { | ||
| file.prepareDuration = state.durations.prepare; | ||
| file.environmentLoad = state.durations.environment; | ||
| // should be collected only for a single test file in a batch | ||
| state.durations.prepare = 0; | ||
| state.durations.environment = 0; | ||
| }); | ||
| // Strip function conditions from retry config before sending via RPC | ||
| // Functions cannot be cloned by structured clone algorithm | ||
| const sanitizeRetryConditions = (task) => { | ||
| if (task.retry && typeof task.retry === "object" && typeof task.retry.condition === "function") | ||
| // Remove function condition - it can't be serialized | ||
| task.retry = { | ||
| ...task.retry, | ||
| condition: void 0 | ||
| }; | ||
| if (task.tasks) task.tasks.forEach(sanitizeRetryConditions); | ||
| }; | ||
| files.forEach(sanitizeRetryConditions); | ||
| rpc().onCollected(files); | ||
| await originalOnCollected?.call(testRunner, files); | ||
| }; | ||
| const originalOnAfterRun = testRunner.onAfterRunFiles; | ||
| testRunner.onAfterRunFiles = async (files) => { | ||
| const state = getWorkerState(); | ||
| const coverage = await takeCoverageInsideWorker(config.coverage, moduleRunner); | ||
| if (coverage) rpc().onAfterSuiteRun({ | ||
| coverage, | ||
| testFiles: files.map((file) => file.name).sort(), | ||
| environment: state.environment.viteEnvironment || state.environment.name, | ||
| projectName: state.ctx.projectName | ||
| }); | ||
| await originalOnAfterRun?.call(testRunner, files); | ||
| }; | ||
| const originalOnAfterRunTask = testRunner.onAfterRunTask; | ||
| testRunner.onAfterRunTask = async (test) => { | ||
| if (config.bail && test.result?.state === "fail") { | ||
| if (1 + await rpc().getCountOfFailedTests() >= config.bail) { | ||
| rpc().onCancel("test-failure"); | ||
| testRunner.cancel?.("test-failure"); | ||
| } | ||
| } | ||
| await originalOnAfterRunTask?.call(testRunner, test); | ||
| }; | ||
| return testRunner; | ||
| } | ||
| export { resolveSnapshotEnvironment as a, detectAsyncLeaks as d, resolveTestRunner as r, setupChaiConfig as s }; |
| import { i as init } from './init.CfiYZpFg.js'; | ||
| if (!process.send) throw new Error("Expected worker to be run in node:child_process"); | ||
| // Store globals in case tests overwrite them | ||
| const processExit = process.exit.bind(process); | ||
| const processSend = process.send.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const processRemoveAllListeners = process.removeAllListeners.bind(process); | ||
| // Work-around for nodejs/node#55094 | ||
| if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit()); | ||
| processOn("error", onError); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (v) => processSend(v), | ||
| on: (cb) => processOn("message", cb), | ||
| off: (cb) => processOff("message", cb), | ||
| teardown: () => { | ||
| processRemoveAllListeners("message"); | ||
| processOff("error", onError); | ||
| }, | ||
| runTests: (state, traces) => executeTests("run", state, traces), | ||
| collectTests: (state, traces) => executeTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| async function executeTests(method, state, traces) { | ||
| try { | ||
| await runTests(method, state, traces); | ||
| } finally { | ||
| process.exit = processExit; | ||
| } | ||
| } | ||
| } | ||
| // Prevent leaving worker in loops where it tries to send message to closed main | ||
| // thread, errors, and tries to send the error. | ||
| function onError(error) { | ||
| if (error?.code === "ERR_IPC_CHANNEL_CLOSED" || error?.code === "EPIPE") processExit(1); | ||
| } | ||
| export { workerInit as w }; |
| import { isMainThread, parentPort } from 'node:worker_threads'; | ||
| import { i as init } from './init.CfiYZpFg.js'; | ||
| if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads"); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (response) => parentPort.postMessage(response), | ||
| on: (callback) => parentPort.on("message", callback), | ||
| off: (callback) => parentPort.off("message", callback), | ||
| teardown: () => parentPort.removeAllListeners("message"), | ||
| runTests: async (state, traces) => runTests("run", state, traces), | ||
| collectTests: async (state, traces) => runTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| } | ||
| export { workerInit as w }; |
| import { readFileSync } from 'node:fs'; | ||
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { ModuleRunner, EvaluatedModules } from 'vite/module-runner'; | ||
| import { e as environments, b as VitestTransport } from './index.DxR-nMjO.js'; | ||
| import { r as resolve } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { b as serializeValue, c as createStackString, p as parseStacktrace } from './source-map.DZdIqpIJ.js'; | ||
| import './index.DzTmMrSM.js'; | ||
| import { m } from './tinyrainbow.Ht9iggcq.js'; | ||
| import { Traces } from '../traces.js'; | ||
| import { o as onCancel, V as VitestEvaluatedModules, a as rpcDone, c as createRuntimeRpc } from './rpc.iNjF664v.js'; | ||
| import { s as setupInspect } from './inspector.CvyFGlXm.js'; | ||
| import { E as EnvironmentTeardownError } from './utils.DYj33du9.js'; | ||
| function isBuiltinEnvironment(env) { | ||
| return env in environments; | ||
| } | ||
| const isWindows = process.platform === "win32"; | ||
| const _loaders = /* @__PURE__ */ new Map(); | ||
| function createEnvironmentLoader(root, rpc) { | ||
| const cachedLoader = _loaders.get(root); | ||
| if (!cachedLoader || cachedLoader.isClosed()) { | ||
| _loaders.delete(root); | ||
| const moduleRunner = new ModuleRunner({ | ||
| hmr: false, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| transport: new VitestTransport({ | ||
| async fetchModule(id, importer, options) { | ||
| const result = await rpc.fetch(id, importer, "__vitest__", options); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| if (isWindows && "externalize" in result) | ||
| // TODO: vitest returns paths for external modules, but Vite returns file:// | ||
| // https://github.com/vitejs/vite/pull/20449 | ||
| result.externalize = isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id) ? result.externalize : pathToFileURL(result.externalize).toString(); | ||
| return result; | ||
| }, | ||
| async resolveId(id, importer) { | ||
| return rpc.resolve(id, importer, "__vitest__"); | ||
| } | ||
| }, new EvaluatedModules(), /* @__PURE__ */ new WeakMap()) | ||
| }); | ||
| _loaders.set(root, moduleRunner); | ||
| } | ||
| return _loaders.get(root); | ||
| } | ||
| async function loadNativeEnvironment(name, root, traces) { | ||
| const packageId = name[0] === "." || name[0] === "/" ? pathToFileURL(resolve(root, name)).toString() : import.meta.resolve(`vitest-environment-${name}`, pathToFileURL(root).toString()); | ||
| return resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => import(packageId))); | ||
| } | ||
| function resolveEnvironmentFromModule(name, packageId, pkg) { | ||
| if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`); | ||
| const environment = pkg.default; | ||
| if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`); | ||
| if (environment.transformMode) { | ||
| console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`); | ||
| // keep for backwards compat | ||
| environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client"; | ||
| } | ||
| return environment; | ||
| } | ||
| async function loadEnvironment(name, root, rpc, traces, viteModuleRunner) { | ||
| if (isBuiltinEnvironment(name)) return { environment: environments[name] }; | ||
| if (!viteModuleRunner) return { environment: await loadNativeEnvironment(name, root, traces) }; | ||
| const loader = createEnvironmentLoader(root, rpc); | ||
| const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await traces.$("vitest.runtime.environment.resolve", () => rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__")))?.id ?? resolve(root, name); | ||
| return { | ||
| environment: resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => loader.import(packageId))), | ||
| loader | ||
| }; | ||
| } | ||
| const cleanupListeners = /* @__PURE__ */ new Set(); | ||
| const moduleRunnerListeners = /* @__PURE__ */ new Set(); | ||
| function onCleanup(cb) { | ||
| cleanupListeners.add(cb); | ||
| } | ||
| async function cleanup() { | ||
| await Promise.all(Array.from(cleanupListeners, (l) => l())); | ||
| } | ||
| function onModuleRunner(cb) { | ||
| moduleRunnerListeners.add(cb); | ||
| } | ||
| function emitModuleRunner(moduleRunner) { | ||
| moduleRunnerListeners.forEach((l) => l(moduleRunner)); | ||
| } | ||
| // Store globals in case tests overwrite them | ||
| const processListeners = process.listeners.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const dispose = []; | ||
| function listenForErrors(state) { | ||
| dispose.forEach((fn) => fn()); | ||
| dispose.length = 0; | ||
| function catchError(err, type, event) { | ||
| const worker = state(); | ||
| // if there is another listener, assume that it's handled by user code | ||
| // one is Vitest's own listener | ||
| if (processListeners(event).length > 1) return; | ||
| const error = serializeValue(err); | ||
| if (typeof error === "object" && error != null) { | ||
| error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0; | ||
| if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath; | ||
| } | ||
| state().rpc.onUnhandledError(error, type); | ||
| } | ||
| const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"); | ||
| const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection"); | ||
| processOn("uncaughtException", uncaughtException); | ||
| processOn("unhandledRejection", unhandledRejection); | ||
| dispose.push(() => { | ||
| processOff("uncaughtException", uncaughtException); | ||
| processOff("unhandledRejection", unhandledRejection); | ||
| }); | ||
| } | ||
| class GetterTracker { | ||
| static EXPORTS_MAX_INVOCATIONS = 1e6; | ||
| invocations = /* @__PURE__ */ new Map(); | ||
| excessiveInvocations = /* @__PURE__ */ new Map(); | ||
| createTracker(moduleId, defineExport) { | ||
| return (name, getter) => { | ||
| const key = `${moduleId}:${name}`; | ||
| defineExport(name, () => { | ||
| const count = (this.invocations.get(key) || 0) + 1; | ||
| this.invocations.set(key, count); | ||
| if (count > GetterTracker.EXPORTS_MAX_INVOCATIONS && !this.excessiveInvocations.has(key)) this.excessiveInvocations.set(key, { | ||
| moduleId, | ||
| exportName: name | ||
| }); | ||
| return getter(); | ||
| }); | ||
| }; | ||
| } | ||
| resetInvocations() { | ||
| this.invocations.clear(); | ||
| this.excessiveInvocations.clear(); | ||
| } | ||
| getExcessiveInvocations() { | ||
| return [...this.excessiveInvocations.values()]; | ||
| } | ||
| } | ||
| const resolvingModules = /* @__PURE__ */ new Set(); | ||
| async function execute(method, ctx, worker, traces) { | ||
| const prepareStart = performance.now(); | ||
| const cleanups = [setupInspect(ctx)]; | ||
| // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread | ||
| const rpc = ctx.rpc; | ||
| try { | ||
| // do not close the RPC channel so that we can get the error messages sent to the main thread | ||
| cleanups.push(async () => { | ||
| await Promise.all(rpc.$rejectPendingCalls(({ method, reject }) => { | ||
| reject(new EnvironmentTeardownError(`[vitest-worker]: Closing rpc while "${method}" was pending`)); | ||
| })); | ||
| }); | ||
| const state = { | ||
| ctx, | ||
| evaluatedModules: new VitestEvaluatedModules(), | ||
| resolvingModules, | ||
| moduleExecutionInfo: /* @__PURE__ */ new Map(), | ||
| config: ctx.config, | ||
| environment: null, | ||
| durations: { | ||
| environment: 0, | ||
| prepare: prepareStart | ||
| }, | ||
| rpc, | ||
| onCancel, | ||
| onCleanup: onCleanup, | ||
| providedContext: ctx.providedContext, | ||
| onFilterStackTrace(stack) { | ||
| return createStackString(parseStacktrace(stack)); | ||
| }, | ||
| metaEnv: ctx.metaEnv, | ||
| getterTracker: ctx.config.benchmark.enabled && !ctx.config.benchmark.suppressExportGetterWarnings ? new GetterTracker() : void 0 | ||
| }; | ||
| const methodName = method === "collect" ? "collectTests" : "runTests"; | ||
| if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`); | ||
| await worker[methodName](state, traces); | ||
| } finally { | ||
| await rpcDone().catch(() => {}); | ||
| await Promise.all(cleanups.map((fn) => fn())).catch(() => {}); | ||
| } | ||
| } | ||
| function run(ctx, worker, traces) { | ||
| return execute("run", ctx, worker, traces); | ||
| } | ||
| function collect(ctx, worker, traces) { | ||
| return execute("collect", ctx, worker, traces); | ||
| } | ||
| async function teardown() { | ||
| await cleanup(); | ||
| } | ||
| // default import: `flushCompileCache` only exists since Node 22.10, a named | ||
| // import would fail to link on older versions | ||
| function createImportMetaEnvProxy() { | ||
| 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; | ||
| } | ||
| }); | ||
| } | ||
| const importMetaEnvProxy = createImportMetaEnvProxy(); | ||
| const __vitest_worker_response__ = true; | ||
| const memoryUsage = process.memoryUsage.bind(process); | ||
| let reportMemory = false; | ||
| let traces; | ||
| /** @experimental */ | ||
| function init(worker) { | ||
| worker.on(onMessage); | ||
| if (worker.onModuleRunner) onModuleRunner(worker.onModuleRunner); | ||
| let runPromise; | ||
| let isRunning = false; | ||
| let workerTeardown; | ||
| let setupContext; | ||
| let poolId; | ||
| function send(response) { | ||
| worker.post(worker.serialize ? worker.serialize(response) : response); | ||
| } | ||
| async function onMessage(rawMessage) { | ||
| const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage; | ||
| if (message?.__vitest_worker_request__ !== true) return; | ||
| switch (message.type) { | ||
| case "start": { | ||
| process.env.VITEST_POOL_ID = String(message.poolId); | ||
| process.env.VITEST_WORKER_ID = String(message.workerId); | ||
| reportMemory = message.options.reportMemory; | ||
| poolId = message.poolId; | ||
| if (message.context.config.disableColors) m(); | ||
| traces ??= await new Traces({ | ||
| enabled: message.traces.enabled, | ||
| sdkPath: message.traces.sdkPath | ||
| }).waitInit(); | ||
| const { environment, config, pool } = message.context; | ||
| const context = traces.getContextFromCarrier(message.traces.otelCarrier); | ||
| // record telemetry as part of "start" | ||
| traces.recordInitSpan(context); | ||
| try { | ||
| setupContext = { | ||
| environment, | ||
| config, | ||
| pool, | ||
| rpc: createRuntimeRpc(worker), | ||
| metaEnv: importMetaEnvProxy, | ||
| projectName: config.name || "", | ||
| traces | ||
| }; | ||
| workerTeardown = await traces.$("vitest.runtime.setup", { context }, () => worker.setup?.(setupContext)); | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__, | ||
| error: serializeValue(error) | ||
| }); | ||
| } | ||
| break; | ||
| } | ||
| case "run": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeValue(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeValue(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.run", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => run({ | ||
| ...setupContext, | ||
| ...message.context, | ||
| concurrencyId: poolId | ||
| }, worker, traces).catch((error) => serializeValue(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "collect": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeValue(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeValue(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.collect", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => collect({ | ||
| ...setupContext, | ||
| ...message.context, | ||
| concurrencyId: poolId | ||
| }, worker, traces).catch((error) => serializeValue(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "stop": { | ||
| await runPromise; | ||
| // Persist this worker's compile cache before the parent tears the | ||
| // worker down — forks are SIGTERM'd and never reach Node's exit-time | ||
| // flush, so without this the cache stays write-only for them. Runs | ||
| // even when teardown throws (the compiled modules are still worth | ||
| // persisting). A no-op when the cache is disabled or was fully loaded | ||
| // from disk, and cheap (~tens of ms) otherwise, so every worker can | ||
| // afford it. | ||
| const persistCompileCache = () => { | ||
| try { | ||
| module$1.flushCompileCache?.(); | ||
| } catch {} | ||
| }; | ||
| try { | ||
| const context = traces.getContextFromCarrier(message.otelCarrier); | ||
| const error = await traces.$("vitest.runtime.teardown", { context }, async () => { | ||
| const error = await teardown().catch((error) => serializeValue(error)); | ||
| await workerTeardown?.(); | ||
| return error; | ||
| }); | ||
| await traces.finish(); | ||
| persistCompileCache(); | ||
| send({ | ||
| type: "stopped", | ||
| error, | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| persistCompileCache(); | ||
| send({ | ||
| type: "stopped", | ||
| error: serializeValue(error), | ||
| __vitest_worker_response__ | ||
| }); | ||
| } | ||
| worker.teardown?.(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function getFilesWithLocations(files) { | ||
| return files.flatMap((file) => { | ||
| if (!file.testLocations) return file.filepath; | ||
| return file.testLocations.map((location) => { | ||
| return `${file}:${location}`; | ||
| }); | ||
| }); | ||
| } | ||
| export { listenForErrors as a, emitModuleRunner as e, init as i, loadEnvironment as l }; |
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| import { MessageChannel } from 'node:worker_threads'; | ||
| import { initSyntaxLexers, hoistMocks } from '@vitest/mocker/transforms'; | ||
| import { c as cleanUrl, r as resolve } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { p as parse } from './acorn.B2iPLyUM.js'; | ||
| import MagicString from 'magic-string'; | ||
| import { y } from './tinyrainbow.Ht9iggcq.js'; | ||
| import { distDir } from '../path.js'; | ||
| import { t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import 'node:path'; | ||
| const NOW_LENGTH = Date.now().toString().length; | ||
| const REGEXP_VITEST = new RegExp(`%3Fvitest=\\d{${NOW_LENGTH}}`); | ||
| const REGEXP_MOCK_ACTUAL = /\?mock=actual/; | ||
| async function setupNodeLoaderHooks(worker) { | ||
| if (module$1.setSourceMapsSupport) module$1.setSourceMapsSupport(true); | ||
| else if (process.setSourceMapsEnabled) process.setSourceMapsEnabled(true); | ||
| if (worker.config.experimental.nodeLoader !== false) await initSyntaxLexers(); | ||
| if (typeof module$1.registerHooks === "function") module$1.registerHooks({ | ||
| resolve(specifier, context, nextResolve) { | ||
| if (specifier.includes("mock=actual")) { | ||
| // url is already resolved by `importActual` | ||
| const moduleId = specifier.replace(REGEXP_MOCK_ACTUAL, ""); | ||
| const builtin = isBuiltin(moduleId); | ||
| return { | ||
| url: builtin ? toBuiltin(moduleId) : moduleId, | ||
| format: builtin ? "builtin" : void 0, | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| const isVitest = specifier.includes("%3Fvitest="); | ||
| const result = nextResolve(isVitest ? specifier.replace(REGEXP_VITEST, "") : specifier, context); | ||
| // avoid tracking /node_modules/ module graph for performance reasons | ||
| if (context.parentURL && result.url && !result.url.includes("/node_modules/")) worker.rpc.ensureModuleGraphEntry(result.url, context.parentURL).catch(() => { | ||
| // ignore errors | ||
| }); | ||
| // this is require for in-source tests to be invalidated if | ||
| // one of the files already imported it in --maxWorkers=1 --no-isolate | ||
| if (isVitest) result.url = `${result.url}?vitest=${Date.now()}`; | ||
| if (worker.config.experimental.nodeLoader === false || !context.parentURL || result.url.includes(distDir) || context.parentURL?.toString().includes(distDir)) return result; | ||
| const mockedResult = getNativeMocker()?.resolveMockedModule(result.url, context.parentURL); | ||
| if (mockedResult != null) return mockedResult; | ||
| return result; | ||
| }, | ||
| load: worker.config.experimental.nodeLoader === false ? void 0 : createLoadHook() | ||
| }); | ||
| else if (module$1.register) { | ||
| if (worker.config.experimental.nodeLoader !== false) console.warn(`${y.bgYellow(" WARNING ")} "module.registerHooks" is not supported in Node.js ${process.version}. This means that some features like module mocking or in-source testing are not supported. Upgrade your Node.js version to at least 22.15 or disable "experimental.nodeLoader" flag manually.\n`); | ||
| const { port1, port2 } = new MessageChannel(); | ||
| port1.unref(); | ||
| port2.unref(); | ||
| port1.on("message", (data) => { | ||
| if (!data || typeof data !== "object") return; | ||
| switch (data.event) { | ||
| case "register-module-graph-entry": { | ||
| const { url, parentURL } = data; | ||
| worker.rpc.ensureModuleGraphEntry(url, parentURL); | ||
| return; | ||
| } | ||
| default: console.error("Unknown message event:", data.event); | ||
| } | ||
| }); | ||
| /** Registers {@link file://./../nodejsWorkerLoader.ts} */ | ||
| module$1.register("#nodejs-worker-loader", { | ||
| parentURL: import.meta.url, | ||
| data: { port: port2 }, | ||
| transferList: [port2] | ||
| }); | ||
| } else if (!process.versions.deno && !process.versions.bun) console.warn("\"module.registerHooks\" and \"module.register\" are not supported. Some Vitest features may not work. Please, use Node.js 18.19.0 or higher."); | ||
| } | ||
| function replaceInSourceMarker(url, source, ms) { | ||
| const re = /import\.meta\.vitest/g; | ||
| let match; | ||
| let overridden = false; | ||
| // eslint-disable-next-line no-cond-assign | ||
| while (match = re.exec(source)) { | ||
| const { index, "0": code } = match; | ||
| overridden = true; | ||
| // should it support process.vitest for CJS modules? | ||
| ms().overwrite(index, index + code.length, "IMPORT_META_TEST()"); | ||
| } | ||
| if (overridden) { | ||
| const filename = resolve(fileURLToPath(url)); | ||
| // appending instead of prepending because functions are hoisted and we don't change the offset | ||
| ms().append(`;\nfunction IMPORT_META_TEST() { return typeof __vitest_worker__ !== 'undefined' && __vitest_worker__.filepath === "${filename.replace(/"/g, "\\\"")}" ? __vitest_index__ : undefined; }`); | ||
| } | ||
| } | ||
| const ignoreFormats = new Set([ | ||
| "addon", | ||
| "builtin", | ||
| "wasm" | ||
| ]); | ||
| function createLoadHook(_worker) { | ||
| return (url, context, nextLoad) => { | ||
| const result = url.includes("mock=") && isBuiltin(cleanUrl(url)) ? { format: "commonjs" } : nextLoad(url, context); | ||
| if (result.format && ignoreFormats.has(result.format) || url.includes(distDir)) return result; | ||
| const mocker = getNativeMocker(); | ||
| mocker?.checkCircularManualMock(url); | ||
| if (url.includes("mock=automock") || url.includes("mock=autospy")) { | ||
| const automockedResult = mocker?.loadAutomock(url, result); | ||
| if (automockedResult != null) return automockedResult; | ||
| return result; | ||
| } | ||
| if (url.includes("mock=manual")) { | ||
| const mockedResult = mocker?.loadManualMock(url, result); | ||
| if (mockedResult != null) return mockedResult; | ||
| return result; | ||
| } | ||
| // ignore non-vitest modules for performance reasons, | ||
| // vi.hoisted and vi.mock won't work outside of test files or setup files | ||
| if (!result.source || !url.includes("vitest=")) return result; | ||
| const filename = url.startsWith("file://") ? fileURLToPath(url) : url; | ||
| const source = result.source.toString(); | ||
| const transformedCode = result.format?.includes("typescript") ? module$1.stripTypeScriptTypes(source) : source; | ||
| let _ms; | ||
| const ms = () => _ms || (_ms = new MagicString(source)); | ||
| if (source.includes("import.meta.vitest")) replaceInSourceMarker(url, source, ms); | ||
| hoistMocks(transformedCode, filename, (code) => parse(code, { | ||
| ecmaVersion: "latest", | ||
| sourceType: result.format === "module" || result.format === "module-typescript" || result.format === "typescript" ? "module" : "script" | ||
| }), { | ||
| magicString: ms, | ||
| globalThisAccessor: "\"__vitest_mocker__\"" | ||
| }); | ||
| let code; | ||
| if (_ms) code = `${_ms.toString()}\n//# sourceMappingURL=${genSourceMapUrl(_ms.generateMap({ | ||
| hires: "boundary", | ||
| source: filename | ||
| }))}`; | ||
| else code = source; | ||
| return { | ||
| format: result.format, | ||
| shortCircuit: true, | ||
| source: code | ||
| }; | ||
| }; | ||
| } | ||
| function genSourceMapUrl(map) { | ||
| if (typeof map !== "string") map = JSON.stringify(map); | ||
| return `data:application/json;base64,${Buffer.from(map).toString("base64")}`; | ||
| } | ||
| function getNativeMocker() { | ||
| return typeof __vitest_mocker__ !== "undefined" ? __vitest_mocker__ : void 0; | ||
| } | ||
| export { setupNodeLoaderHooks }; |
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import { automockModule, createManualModuleSource, collectModuleExports } from '@vitest/mocker/transforms'; | ||
| import { c as cleanUrl, e as createDefer, i as isAbsolute } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { p as parse } from './acorn.B2iPLyUM.js'; | ||
| import { t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { B as BareModuleMocker, n as normalizeModuleId } from './index.DxR-nMjO.js'; | ||
| import 'node:fs'; | ||
| import './utils.DYj33du9.js'; | ||
| import '../path.js'; | ||
| import 'node:path'; | ||
| import '../module-evaluator.js'; | ||
| import 'node:vm'; | ||
| import 'vite/module-runner'; | ||
| import '../traces.js'; | ||
| import '@vitest/mocker'; | ||
| import '@vitest/mocker/redirect'; | ||
| import 'node:console'; | ||
| class NativeModuleMocker extends BareModuleMocker { | ||
| wrapDynamicImport(moduleFactory) { | ||
| if (typeof moduleFactory === "function") return new Promise((resolve, reject) => { | ||
| this.resolveMocks().finally(() => { | ||
| moduleFactory().then(resolve, reject); | ||
| }); | ||
| }); | ||
| return moduleFactory; | ||
| } | ||
| resolveMockedModule(url, parentURL) { | ||
| // don't mock modules inside of packages because there is | ||
| // a high chance that it uses `require` which is not mockable | ||
| // because we use top-level await in "manual" mocks. | ||
| // for the sake of consistency we don't support mocking anything at all | ||
| if (parentURL.includes("/node_modules/")) return; | ||
| const moduleId = normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url); | ||
| const mockedModule = this.getDependencyMock(moduleId); | ||
| if (!mockedModule) return; | ||
| if (mockedModule.type === "redirect") return { | ||
| url: pathToFileURL(mockedModule.redirect).toString(), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "automock" || mockedModule.type === "autospy") return { | ||
| url: injectQuery(url, parentURL, `mock=${mockedModule.type}`), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "manual") return { | ||
| url: injectQuery(url, parentURL, "mock=manual"), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| loadAutomock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| let source; | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(moduleId); | ||
| const exports$1 = Object.keys(builtinModule); | ||
| source = ` | ||
| import * as builtinModule from '${toBuiltin(moduleId)}?mock=actual' | ||
| ${exports$1.map((key, index) => { | ||
| return ` | ||
| const __${index} = builtinModule["${key}"] | ||
| export { __${index} as "${key}" } | ||
| `; | ||
| }).join("")}`; | ||
| } else source = result.source?.toString(); | ||
| if (source == null) return; | ||
| const mockType = url.includes("mock=automock") ? "automock" : "autospy"; | ||
| const transformedCode = transformCode(source, result.format || "module", moduleId); | ||
| try { | ||
| const ms = automockModule(transformedCode, mockType, (code) => parse(code, { | ||
| sourceType: "module", | ||
| ecmaVersion: "latest" | ||
| }), { id: moduleId }); | ||
| return { | ||
| format: "module", | ||
| source: `${ms.toString()}\n//# sourceMappingURL=${genSourceMapUrl(ms.generateMap({ | ||
| hires: "boundary", | ||
| source: moduleId | ||
| }))}`, | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Cannot automock '${url}' because it failed to parse.`, { cause }); | ||
| } | ||
| } | ||
| loadManualMock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| // should not be possible | ||
| if (this.getDependencyMock(moduleId)?.type !== "manual") { | ||
| console.warn(`Vitest detected unregistered manual mock ${moduleId}. This is a bug in Vitest. Please, open a new issue with reproduction.`); | ||
| return; | ||
| } | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(toBuiltin(moduleId)); | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, Object.keys(builtinModule)), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| if (!result.source) return; | ||
| const transformedCode = transformCode(result.source.toString(), result.format || "module", moduleId); | ||
| if (transformedCode == null) return; | ||
| const format = result.format?.startsWith("module") ? "module" : "commonjs"; | ||
| try { | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, collectModuleExports(moduleId, transformedCode, format)), | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Failed to mock '${url}'. See the cause for more information.`, { cause }); | ||
| } | ||
| } | ||
| processedModules = /* @__PURE__ */ new Map(); | ||
| checkCircularManualMock(url) { | ||
| const id = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 0) + 1); | ||
| // the module is mocked and requested a second time, let's resolve | ||
| // the factory function that will redefine the exports later | ||
| if (this.originalModulePromises.has(id)) { | ||
| const factoryPromise = this.factoryPromises.get(id); | ||
| this.originalModulePromises.get(id)?.resolve({ __factoryPromise: factoryPromise }); | ||
| } | ||
| } | ||
| originalModulePromises = /* @__PURE__ */ new Map(); | ||
| factoryPromises = /* @__PURE__ */ new Map(); | ||
| // potential performance improvement: | ||
| // store by URL, not ids, no need to call url.*to* methods and normalizeModuleId | ||
| getFactoryModule(id) { | ||
| const mock = this.getMockerRegistry().getById(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 mockResult = mock.resolve(); | ||
| if (mockResult instanceof Promise) { | ||
| // to avoid circular dependency, we resolve this function as {__factoryPromise} in `checkCircularManualMock` | ||
| // when it's requested the second time. then the exports are exposed as `undefined`, | ||
| // but later redefined when the promise is actually resolved | ||
| const promise = createDefer(); | ||
| promise.finally(() => { | ||
| this.originalModulePromises.delete(id); | ||
| }); | ||
| mockResult.then(promise.resolve, promise.reject).finally(() => { | ||
| this.factoryPromises.delete(id); | ||
| }); | ||
| this.factoryPromises.set(id, mockResult); | ||
| this.originalModulePromises.set(id, promise); | ||
| // Node.js on windows processes all the files first, and then runs them | ||
| // unlike Node.js logic on Mac and Unix where it also runs the code while evaluating | ||
| // So on Linux/Mac this `if` won't be hit because `checkCircularManualMock` will resolve it | ||
| // And on Windows, the `checkCircularManualMock` will never have `originalModulePromises` | ||
| // because `getFactoryModule` is not called until the evaluation phase | ||
| // But if we track how many times the module was transformed, | ||
| // we can deduce when to return `__factoryPromise` to support circular modules | ||
| if ((this.processedModules.get(id) ?? 0) > 1) { | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 1) - 1); | ||
| promise.resolve({ __factoryPromise: mockResult }); | ||
| } | ||
| return promise; | ||
| } | ||
| return mockResult; | ||
| } | ||
| importActual(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "actual"); | ||
| return import(url.toString()); | ||
| } | ||
| importMock(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| // file is already mocked | ||
| if (resolvedId.includes("mock=")) return import(resolvedId); | ||
| const filename = fileURLToPath(resolvedId); | ||
| const external = !isAbsolute(filename) || this.isModuleDirectory(resolvedId) ? normalizeModuleId(rawId) : null; | ||
| // file is not mocked, automock or redirect it | ||
| const redirect = this.findMockRedirect(filename, external); | ||
| if (redirect) return import(pathToFileURL(redirect).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "automock"); | ||
| return import(url.toString()); | ||
| } | ||
| } | ||
| const replacePercentageRE = /%/g; | ||
| function injectQuery(url, importer, queryToInject) { | ||
| const { search, hash } = new URL(url.replace(replacePercentageRE, "%25"), importer); | ||
| return `${cleanUrl(url)}?${queryToInject}${search ? `&${search.slice(1)}` : ""}${hash ?? ""}`; | ||
| } | ||
| let __require; | ||
| function getBuiltinModule(moduleId) { | ||
| __require ??= module$1.createRequire(import.meta.url); | ||
| return __require(`${moduleId}?mock=actual`); | ||
| } | ||
| function genSourceMapUrl(map) { | ||
| if (typeof map !== "string") map = JSON.stringify(map); | ||
| return `data:application/json;base64,${Buffer.from(map).toString("base64")}`; | ||
| } | ||
| function transformCode(code, format, filename) { | ||
| if (format.includes("typescript")) { | ||
| if (!module$1.stripTypeScriptTypes) throw new Error(`Cannot parse '${filename}' because "module.stripTypeScriptTypes" is not supported. Module mocking requires Node.js 22.15 or higher. This is NOT a bug of Vitest.`); | ||
| return module$1.stripTypeScriptTypes(code); | ||
| } | ||
| return code; | ||
| } | ||
| export { NativeModuleMocker }; |
| import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1, URL as URL$1 } from 'node:url'; | ||
| import fs__default, { statSync, realpathSync } from 'node:fs'; | ||
| import { builtinModules, createRequire } from 'node:module'; | ||
| import path, { win32, dirname, join } from 'node:path'; | ||
| import process$1 from 'node:process'; | ||
| import fs from 'node:fs/promises'; | ||
| import assert from 'node:assert'; | ||
| import v8 from 'node:v8'; | ||
| import { format, inspect } from 'node:util'; | ||
| import { i as isAbsolute, r as resolve } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { ModuleRunner } from 'vite/module-runner'; | ||
| const JOIN_LEADING_SLASH_RE = /^\.?\//; | ||
| function withTrailingSlash(input = "", respectQueryAndFragment) { | ||
| { | ||
| return input.endsWith("/") ? input : input + "/"; | ||
| } | ||
| } | ||
| function isNonEmptyURL(url) { | ||
| return url && url !== "/"; | ||
| } | ||
| function joinURL(base, ...input) { | ||
| let url = base || ""; | ||
| for (const segment of input.filter((url2) => isNonEmptyURL(url2))) { | ||
| if (url) { | ||
| const _segment = segment.replace(JOIN_LEADING_SLASH_RE, ""); | ||
| url = withTrailingSlash(url) + _segment; | ||
| } else { | ||
| url = segment; | ||
| } | ||
| } | ||
| return url; | ||
| } | ||
| const BUILTIN_MODULES = new Set(builtinModules); | ||
| function normalizeSlash(path) { | ||
| return path.replace(/\\/g, "/"); | ||
| } | ||
| /** | ||
| * @typedef ErrnoExceptionFields | ||
| * @property {number | undefined} [errnode] | ||
| * @property {string | undefined} [code] | ||
| * @property {string | undefined} [path] | ||
| * @property {string | undefined} [syscall] | ||
| * @property {string | undefined} [url] | ||
| * | ||
| * @typedef {Error & ErrnoExceptionFields} ErrnoException | ||
| */ | ||
| const own$1 = {}.hasOwnProperty; | ||
| const classRegExp = /^([A-Z][a-z\d]*)+$/; | ||
| // Sorted by a rough estimate on most frequently used entries. | ||
| const kTypes = new Set([ | ||
| 'string', | ||
| 'function', | ||
| 'number', | ||
| 'object', | ||
| // Accept 'Function' and 'Object' as alternative to the lower cased version. | ||
| 'Function', | ||
| 'Object', | ||
| 'boolean', | ||
| 'bigint', | ||
| 'symbol' | ||
| ]); | ||
| const codes = {}; | ||
| /** | ||
| * Create a list string in the form like 'A and B' or 'A, B, ..., and Z'. | ||
| * We cannot use Intl.ListFormat because it's not available in | ||
| * --without-intl builds. | ||
| * | ||
| * @param {Array<string>} array | ||
| * An array of strings. | ||
| * @param {string} [type] | ||
| * The list type to be inserted before the last element. | ||
| * @returns {string} | ||
| */ | ||
| function formatList(array, type = 'and') { | ||
| return array.length < 3 | ||
| ? array.join(` ${type} `) | ||
| : `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}` | ||
| } | ||
| /** @type {Map<string, MessageFunction | string>} */ | ||
| const messages = new Map(); | ||
| const nodeInternalPrefix = '__node_internal_'; | ||
| /** @type {number} */ | ||
| let userStackTraceLimit; | ||
| codes.ERR_INVALID_ARG_TYPE = createError( | ||
| 'ERR_INVALID_ARG_TYPE', | ||
| /** | ||
| * @param {string} name | ||
| * @param {Array<string> | string} expected | ||
| * @param {unknown} actual | ||
| */ | ||
| (name, expected, actual) => { | ||
| assert(typeof name === 'string', "'name' must be a string"); | ||
| if (!Array.isArray(expected)) { | ||
| expected = [expected]; | ||
| } | ||
| let message = 'The '; | ||
| if (name.endsWith(' argument')) { | ||
| // For cases like 'first argument' | ||
| message += `${name} `; | ||
| } else { | ||
| const type = name.includes('.') ? 'property' : 'argument'; | ||
| message += `"${name}" ${type} `; | ||
| } | ||
| message += 'must be '; | ||
| /** @type {Array<string>} */ | ||
| const types = []; | ||
| /** @type {Array<string>} */ | ||
| const instances = []; | ||
| /** @type {Array<string>} */ | ||
| const other = []; | ||
| for (const value of expected) { | ||
| assert( | ||
| typeof value === 'string', | ||
| 'All expected entries have to be of type string' | ||
| ); | ||
| if (kTypes.has(value)) { | ||
| types.push(value.toLowerCase()); | ||
| } else if (classRegExp.exec(value) === null) { | ||
| assert( | ||
| value !== 'object', | ||
| 'The value "object" should be written as "Object"' | ||
| ); | ||
| other.push(value); | ||
| } else { | ||
| instances.push(value); | ||
| } | ||
| } | ||
| // Special handle `object` in case other instances are allowed to outline | ||
| // the differences between each other. | ||
| if (instances.length > 0) { | ||
| const pos = types.indexOf('object'); | ||
| if (pos !== -1) { | ||
| types.slice(pos, 1); | ||
| instances.push('Object'); | ||
| } | ||
| } | ||
| if (types.length > 0) { | ||
| message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList( | ||
| types, | ||
| 'or' | ||
| )}`; | ||
| if (instances.length > 0 || other.length > 0) message += ' or '; | ||
| } | ||
| if (instances.length > 0) { | ||
| message += `an instance of ${formatList(instances, 'or')}`; | ||
| if (other.length > 0) message += ' or '; | ||
| } | ||
| if (other.length > 0) { | ||
| if (other.length > 1) { | ||
| message += `one of ${formatList(other, 'or')}`; | ||
| } else { | ||
| if (other[0].toLowerCase() !== other[0]) message += 'an '; | ||
| message += `${other[0]}`; | ||
| } | ||
| } | ||
| message += `. Received ${determineSpecificType(actual)}`; | ||
| return message | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_INVALID_MODULE_SPECIFIER = createError( | ||
| 'ERR_INVALID_MODULE_SPECIFIER', | ||
| /** | ||
| * @param {string} request | ||
| * @param {string} reason | ||
| * @param {string} [base] | ||
| */ | ||
| (request, reason, base = undefined) => { | ||
| return `Invalid module "${request}" ${reason}${ | ||
| base ? ` imported from ${base}` : '' | ||
| }` | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_INVALID_PACKAGE_CONFIG = createError( | ||
| 'ERR_INVALID_PACKAGE_CONFIG', | ||
| /** | ||
| * @param {string} path | ||
| * @param {string} [base] | ||
| * @param {string} [message] | ||
| */ | ||
| (path, base, message) => { | ||
| return `Invalid package config ${path}${ | ||
| base ? ` while importing ${base}` : '' | ||
| }${message ? `. ${message}` : ''}` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_INVALID_PACKAGE_TARGET = createError( | ||
| 'ERR_INVALID_PACKAGE_TARGET', | ||
| /** | ||
| * @param {string} packagePath | ||
| * @param {string} key | ||
| * @param {unknown} target | ||
| * @param {boolean} [isImport=false] | ||
| * @param {string} [base] | ||
| */ | ||
| (packagePath, key, target, isImport = false, base = undefined) => { | ||
| const relatedError = | ||
| typeof target === 'string' && | ||
| !isImport && | ||
| target.length > 0 && | ||
| !target.startsWith('./'); | ||
| if (key === '.') { | ||
| assert(isImport === false); | ||
| return ( | ||
| `Invalid "exports" main target ${JSON.stringify(target)} defined ` + | ||
| `in the package config ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }${relatedError ? '; targets must start with "./"' : ''}` | ||
| ) | ||
| } | ||
| return `Invalid "${ | ||
| isImport ? 'imports' : 'exports' | ||
| }" target ${JSON.stringify( | ||
| target | ||
| )} defined for '${key}' in the package config ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }${relatedError ? '; targets must start with "./"' : ''}` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_MODULE_NOT_FOUND = createError( | ||
| 'ERR_MODULE_NOT_FOUND', | ||
| /** | ||
| * @param {string} path | ||
| * @param {string} base | ||
| * @param {boolean} [exactUrl] | ||
| */ | ||
| (path, base, exactUrl = false) => { | ||
| return `Cannot find ${ | ||
| exactUrl ? 'module' : 'package' | ||
| } '${path}' imported from ${base}` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_NETWORK_IMPORT_DISALLOWED = createError( | ||
| 'ERR_NETWORK_IMPORT_DISALLOWED', | ||
| "import of '%s' by %s is not supported: %s", | ||
| Error | ||
| ); | ||
| codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError( | ||
| 'ERR_PACKAGE_IMPORT_NOT_DEFINED', | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {string} packagePath | ||
| * @param {string} base | ||
| */ | ||
| (specifier, packagePath, base) => { | ||
| return `Package import specifier "${specifier}" is not defined${ | ||
| packagePath ? ` in package ${packagePath}package.json` : '' | ||
| } imported from ${base}` | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError( | ||
| 'ERR_PACKAGE_PATH_NOT_EXPORTED', | ||
| /** | ||
| * @param {string} packagePath | ||
| * @param {string} subpath | ||
| * @param {string} [base] | ||
| */ | ||
| (packagePath, subpath, base = undefined) => { | ||
| if (subpath === '.') | ||
| return `No "exports" main defined in ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }` | ||
| return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_UNSUPPORTED_DIR_IMPORT = createError( | ||
| 'ERR_UNSUPPORTED_DIR_IMPORT', | ||
| "Directory import '%s' is not supported " + | ||
| 'resolving ES modules imported from %s', | ||
| Error | ||
| ); | ||
| codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError( | ||
| 'ERR_UNSUPPORTED_RESOLVE_REQUEST', | ||
| 'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.', | ||
| TypeError | ||
| ); | ||
| codes.ERR_UNKNOWN_FILE_EXTENSION = createError( | ||
| 'ERR_UNKNOWN_FILE_EXTENSION', | ||
| /** | ||
| * @param {string} extension | ||
| * @param {string} path | ||
| */ | ||
| (extension, path) => { | ||
| return `Unknown file extension "${extension}" for ${path}` | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_INVALID_ARG_VALUE = createError( | ||
| 'ERR_INVALID_ARG_VALUE', | ||
| /** | ||
| * @param {string} name | ||
| * @param {unknown} value | ||
| * @param {string} [reason='is invalid'] | ||
| */ | ||
| (name, value, reason = 'is invalid') => { | ||
| let inspected = inspect(value); | ||
| if (inspected.length > 128) { | ||
| inspected = `${inspected.slice(0, 128)}...`; | ||
| } | ||
| const type = name.includes('.') ? 'property' : 'argument'; | ||
| return `The ${type} '${name}' ${reason}. Received ${inspected}` | ||
| }, | ||
| TypeError | ||
| // Note: extra classes have been shaken out. | ||
| // , RangeError | ||
| ); | ||
| /** | ||
| * Utility function for registering the error codes. Only used here. Exported | ||
| * *only* to allow for testing. | ||
| * @param {string} sym | ||
| * @param {MessageFunction | string} value | ||
| * @param {ErrorConstructor} constructor | ||
| * @returns {new (...parameters: Array<any>) => Error} | ||
| */ | ||
| function createError(sym, value, constructor) { | ||
| // Special case for SystemError that formats the error message differently | ||
| // The SystemErrors only have SystemError as their base classes. | ||
| messages.set(sym, value); | ||
| return makeNodeErrorWithCode(constructor, sym) | ||
| } | ||
| /** | ||
| * @param {ErrorConstructor} Base | ||
| * @param {string} key | ||
| * @returns {ErrorConstructor} | ||
| */ | ||
| function makeNodeErrorWithCode(Base, key) { | ||
| // @ts-expect-error It’s a Node error. | ||
| return NodeError | ||
| /** | ||
| * @param {Array<unknown>} parameters | ||
| */ | ||
| function NodeError(...parameters) { | ||
| const limit = Error.stackTraceLimit; | ||
| if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0; | ||
| const error = new Base(); | ||
| // Reset the limit and setting the name property. | ||
| if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit; | ||
| const message = getMessage(key, parameters, error); | ||
| Object.defineProperties(error, { | ||
| // Note: no need to implement `kIsNodeError` symbol, would be hard, | ||
| // probably. | ||
| message: { | ||
| value: message, | ||
| enumerable: false, | ||
| writable: true, | ||
| configurable: true | ||
| }, | ||
| toString: { | ||
| /** @this {Error} */ | ||
| value() { | ||
| return `${this.name} [${key}]: ${this.message}` | ||
| }, | ||
| enumerable: false, | ||
| writable: true, | ||
| configurable: true | ||
| } | ||
| }); | ||
| captureLargerStackTrace(error); | ||
| // @ts-expect-error It’s a Node error. | ||
| error.code = key; | ||
| return error | ||
| } | ||
| } | ||
| /** | ||
| * @returns {boolean} | ||
| */ | ||
| function isErrorStackTraceLimitWritable() { | ||
| // Do no touch Error.stackTraceLimit as V8 would attempt to install | ||
| // it again during deserialization. | ||
| try { | ||
| if (v8.startupSnapshot.isBuildingSnapshot()) { | ||
| return false | ||
| } | ||
| } catch {} | ||
| const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit'); | ||
| if (desc === undefined) { | ||
| return Object.isExtensible(Error) | ||
| } | ||
| return own$1.call(desc, 'writable') && desc.writable !== undefined | ||
| ? desc.writable | ||
| : desc.set !== undefined | ||
| } | ||
| /** | ||
| * This function removes unnecessary frames from Node.js core errors. | ||
| * @template {(...parameters: unknown[]) => unknown} T | ||
| * @param {T} wrappedFunction | ||
| * @returns {T} | ||
| */ | ||
| function hideStackFrames(wrappedFunction) { | ||
| // We rename the functions that will be hidden to cut off the stacktrace | ||
| // at the outermost one | ||
| const hidden = nodeInternalPrefix + wrappedFunction.name; | ||
| Object.defineProperty(wrappedFunction, 'name', {value: hidden}); | ||
| return wrappedFunction | ||
| } | ||
| const captureLargerStackTrace = hideStackFrames( | ||
| /** | ||
| * @param {Error} error | ||
| * @returns {Error} | ||
| */ | ||
| // @ts-expect-error: fine | ||
| function (error) { | ||
| const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable(); | ||
| if (stackTraceLimitIsWritable) { | ||
| userStackTraceLimit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = Number.POSITIVE_INFINITY; | ||
| } | ||
| Error.captureStackTrace(error); | ||
| // Reset the limit | ||
| if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit; | ||
| return error | ||
| } | ||
| ); | ||
| /** | ||
| * @param {string} key | ||
| * @param {Array<unknown>} parameters | ||
| * @param {Error} self | ||
| * @returns {string} | ||
| */ | ||
| function getMessage(key, parameters, self) { | ||
| const message = messages.get(key); | ||
| assert(message !== undefined, 'expected `message` to be found'); | ||
| if (typeof message === 'function') { | ||
| assert( | ||
| message.length <= parameters.length, // Default options do not count. | ||
| `Code: ${key}; The provided arguments length (${parameters.length}) does not ` + | ||
| `match the required ones (${message.length}).` | ||
| ); | ||
| return Reflect.apply(message, self, parameters) | ||
| } | ||
| const regex = /%[dfijoOs]/g; | ||
| let expectedLength = 0; | ||
| while (regex.exec(message) !== null) expectedLength++; | ||
| assert( | ||
| expectedLength === parameters.length, | ||
| `Code: ${key}; The provided arguments length (${parameters.length}) does not ` + | ||
| `match the required ones (${expectedLength}).` | ||
| ); | ||
| if (parameters.length === 0) return message | ||
| parameters.unshift(message); | ||
| return Reflect.apply(format, null, parameters) | ||
| } | ||
| /** | ||
| * Determine the specific type of a value for type-mismatch errors. | ||
| * @param {unknown} value | ||
| * @returns {string} | ||
| */ | ||
| function determineSpecificType(value) { | ||
| if (value === null || value === undefined) { | ||
| return String(value) | ||
| } | ||
| if (typeof value === 'function' && value.name) { | ||
| return `function ${value.name}` | ||
| } | ||
| if (typeof value === 'object') { | ||
| if (value.constructor && value.constructor.name) { | ||
| return `an instance of ${value.constructor.name}` | ||
| } | ||
| return `${inspect(value, {depth: -1})}` | ||
| } | ||
| let inspected = inspect(value, {colors: false}); | ||
| if (inspected.length > 28) { | ||
| inspected = `${inspected.slice(0, 25)}...`; | ||
| } | ||
| return `type ${typeof value} (${inspected})` | ||
| } | ||
| // Manually “tree shaken” from: | ||
| // <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/package_json_reader.js> | ||
| // Last checked on: Apr 29, 2023. | ||
| // Removed the native dependency. | ||
| // Also: no need to cache, we do that in resolve already. | ||
| const hasOwnProperty$1 = {}.hasOwnProperty; | ||
| const {ERR_INVALID_PACKAGE_CONFIG: ERR_INVALID_PACKAGE_CONFIG$1} = codes; | ||
| /** @type {Map<string, PackageConfig>} */ | ||
| const cache = new Map(); | ||
| /** | ||
| * @param {string} jsonPath | ||
| * @param {{specifier: URL | string, base?: URL}} options | ||
| * @returns {PackageConfig} | ||
| */ | ||
| function read(jsonPath, {base, specifier}) { | ||
| const existing = cache.get(jsonPath); | ||
| if (existing) { | ||
| return existing | ||
| } | ||
| /** @type {string | undefined} */ | ||
| let string; | ||
| try { | ||
| string = fs__default.readFileSync(path.toNamespacedPath(jsonPath), 'utf8'); | ||
| } catch (error) { | ||
| const exception = /** @type {ErrnoException} */ (error); | ||
| if (exception.code !== 'ENOENT') { | ||
| throw exception | ||
| } | ||
| } | ||
| /** @type {PackageConfig} */ | ||
| const result = { | ||
| exists: false, | ||
| pjsonPath: jsonPath, | ||
| main: undefined, | ||
| name: undefined, | ||
| type: 'none', // Ignore unknown types for forwards compatibility | ||
| exports: undefined, | ||
| imports: undefined | ||
| }; | ||
| if (string !== undefined) { | ||
| /** @type {Record<string, unknown>} */ | ||
| let parsed; | ||
| try { | ||
| parsed = JSON.parse(string); | ||
| } catch (error_) { | ||
| const cause = /** @type {ErrnoException} */ (error_); | ||
| const error = new ERR_INVALID_PACKAGE_CONFIG$1( | ||
| jsonPath, | ||
| (base ? `"${specifier}" from ` : '') + fileURLToPath$1(base || specifier), | ||
| cause.message | ||
| ); | ||
| error.cause = cause; | ||
| throw error | ||
| } | ||
| result.exists = true; | ||
| if ( | ||
| hasOwnProperty$1.call(parsed, 'name') && | ||
| typeof parsed.name === 'string' | ||
| ) { | ||
| result.name = parsed.name; | ||
| } | ||
| if ( | ||
| hasOwnProperty$1.call(parsed, 'main') && | ||
| typeof parsed.main === 'string' | ||
| ) { | ||
| result.main = parsed.main; | ||
| } | ||
| if (hasOwnProperty$1.call(parsed, 'exports')) { | ||
| // @ts-expect-error: assume valid. | ||
| result.exports = parsed.exports; | ||
| } | ||
| if (hasOwnProperty$1.call(parsed, 'imports')) { | ||
| // @ts-expect-error: assume valid. | ||
| result.imports = parsed.imports; | ||
| } | ||
| // Ignore unknown types for forwards compatibility | ||
| if ( | ||
| hasOwnProperty$1.call(parsed, 'type') && | ||
| (parsed.type === 'commonjs' || parsed.type === 'module') | ||
| ) { | ||
| result.type = parsed.type; | ||
| } | ||
| } | ||
| cache.set(jsonPath, result); | ||
| return result | ||
| } | ||
| /** | ||
| * @param {URL | string} resolved | ||
| * @returns {PackageConfig} | ||
| */ | ||
| function getPackageScopeConfig(resolved) { | ||
| // Note: in Node, this is now a native module. | ||
| let packageJSONUrl = new URL('package.json', resolved); | ||
| while (true) { | ||
| const packageJSONPath = packageJSONUrl.pathname; | ||
| if (packageJSONPath.endsWith('node_modules/package.json')) { | ||
| break | ||
| } | ||
| const packageConfig = read(fileURLToPath$1(packageJSONUrl), { | ||
| specifier: resolved | ||
| }); | ||
| if (packageConfig.exists) { | ||
| return packageConfig | ||
| } | ||
| const lastPackageJSONUrl = packageJSONUrl; | ||
| packageJSONUrl = new URL('../package.json', packageJSONUrl); | ||
| // Terminates at root where ../package.json equals ../../package.json | ||
| // (can't just check "/package.json" for Windows support). | ||
| if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { | ||
| break | ||
| } | ||
| } | ||
| const packageJSONPath = fileURLToPath$1(packageJSONUrl); | ||
| // ^^ Note: in Node, this is now a native module. | ||
| return { | ||
| pjsonPath: packageJSONPath, | ||
| exists: false, | ||
| type: 'none' | ||
| } | ||
| } | ||
| /** | ||
| * Returns the package type for a given URL. | ||
| * @param {URL} url - The URL to get the package type for. | ||
| * @returns {PackageType} | ||
| */ | ||
| function getPackageType(url) { | ||
| // To do @anonrig: Write a C++ function that returns only "type". | ||
| return getPackageScopeConfig(url).type | ||
| } | ||
| // Manually “tree shaken” from: | ||
| // <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js> | ||
| // Last checked on: Apr 29, 2023. | ||
| const {ERR_UNKNOWN_FILE_EXTENSION} = codes; | ||
| const hasOwnProperty = {}.hasOwnProperty; | ||
| /** @type {Record<string, string>} */ | ||
| const extensionFormatMap = { | ||
| // @ts-expect-error: hush. | ||
| __proto__: null, | ||
| '.cjs': 'commonjs', | ||
| '.js': 'module', | ||
| '.json': 'json', | ||
| '.mjs': 'module' | ||
| }; | ||
| /** | ||
| * @param {string | null} mime | ||
| * @returns {string | null} | ||
| */ | ||
| function mimeToFormat(mime) { | ||
| if ( | ||
| mime && | ||
| /\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i.test(mime) | ||
| ) | ||
| return 'module' | ||
| if (mime === 'application/json') return 'json' | ||
| return null | ||
| } | ||
| /** | ||
| * @callback ProtocolHandler | ||
| * @param {URL} parsed | ||
| * @param {{parentURL: string, source?: Buffer}} context | ||
| * @param {boolean} ignoreErrors | ||
| * @returns {string | null | void} | ||
| */ | ||
| /** | ||
| * @type {Record<string, ProtocolHandler>} | ||
| */ | ||
| const protocolHandlers = { | ||
| // @ts-expect-error: hush. | ||
| __proto__: null, | ||
| 'data:': getDataProtocolModuleFormat, | ||
| 'file:': getFileProtocolModuleFormat, | ||
| 'http:': getHttpProtocolModuleFormat, | ||
| 'https:': getHttpProtocolModuleFormat, | ||
| 'node:'() { | ||
| return 'builtin' | ||
| } | ||
| }; | ||
| /** | ||
| * @param {URL} parsed | ||
| */ | ||
| function getDataProtocolModuleFormat(parsed) { | ||
| const {1: mime} = /^([^/]+\/[^;,]+)[^,]*?(;base64)?,/.exec( | ||
| parsed.pathname | ||
| ) || [null, null, null]; | ||
| return mimeToFormat(mime) | ||
| } | ||
| /** | ||
| * Returns the file extension from a URL. | ||
| * | ||
| * Should give similar result to | ||
| * `require('node:path').extname(require('node:url').fileURLToPath(url))` | ||
| * when used with a `file:` URL. | ||
| * | ||
| * @param {URL} url | ||
| * @returns {string} | ||
| */ | ||
| function extname(url) { | ||
| const pathname = url.pathname; | ||
| let index = pathname.length; | ||
| while (index--) { | ||
| const code = pathname.codePointAt(index); | ||
| if (code === 47 /* `/` */) { | ||
| return '' | ||
| } | ||
| if (code === 46 /* `.` */) { | ||
| return pathname.codePointAt(index - 1) === 47 /* `/` */ | ||
| ? '' | ||
| : pathname.slice(index) | ||
| } | ||
| } | ||
| return '' | ||
| } | ||
| /** | ||
| * @type {ProtocolHandler} | ||
| */ | ||
| function getFileProtocolModuleFormat(url, _context, ignoreErrors) { | ||
| const value = extname(url); | ||
| if (value === '.js') { | ||
| const packageType = getPackageType(url); | ||
| if (packageType !== 'none') { | ||
| return packageType | ||
| } | ||
| return 'commonjs' | ||
| } | ||
| if (value === '') { | ||
| const packageType = getPackageType(url); | ||
| // Legacy behavior | ||
| if (packageType === 'none' || packageType === 'commonjs') { | ||
| return 'commonjs' | ||
| } | ||
| // Note: we don’t implement WASM, so we don’t need | ||
| // `getFormatOfExtensionlessFile` from `formats`. | ||
| return 'module' | ||
| } | ||
| const format = extensionFormatMap[value]; | ||
| if (format) return format | ||
| // Explicit undefined return indicates load hook should rerun format check | ||
| if (ignoreErrors) { | ||
| return undefined | ||
| } | ||
| const filepath = fileURLToPath$1(url); | ||
| throw new ERR_UNKNOWN_FILE_EXTENSION(value, filepath) | ||
| } | ||
| function getHttpProtocolModuleFormat() { | ||
| // To do: HTTPS imports. | ||
| } | ||
| /** | ||
| * @param {URL} url | ||
| * @param {{parentURL: string}} context | ||
| * @returns {string | null} | ||
| */ | ||
| function defaultGetFormatWithoutErrors(url, context) { | ||
| const protocol = url.protocol; | ||
| if (!hasOwnProperty.call(protocolHandlers, protocol)) { | ||
| return null | ||
| } | ||
| return protocolHandlers[protocol](url, context, true) || null | ||
| } | ||
| // Manually “tree shaken” from: | ||
| // <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/resolve.js> | ||
| // Last checked on: Apr 29, 2023. | ||
| const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace]; | ||
| const { | ||
| ERR_INVALID_MODULE_SPECIFIER, | ||
| ERR_INVALID_PACKAGE_CONFIG, | ||
| ERR_INVALID_PACKAGE_TARGET, | ||
| ERR_MODULE_NOT_FOUND, | ||
| ERR_PACKAGE_IMPORT_NOT_DEFINED, | ||
| ERR_PACKAGE_PATH_NOT_EXPORTED, | ||
| ERR_UNSUPPORTED_DIR_IMPORT, | ||
| ERR_UNSUPPORTED_RESOLVE_REQUEST | ||
| } = codes; | ||
| const own = {}.hasOwnProperty; | ||
| const invalidSegmentRegEx = | ||
| /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i; | ||
| const deprecatedInvalidSegmentRegEx = | ||
| /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; | ||
| const invalidPackageNameRegEx = /^\.|%|\\/; | ||
| const patternRegEx = /\*/g; | ||
| const encodedSeparatorRegEx = /%2f|%5c/i; | ||
| /** @type {Set<string>} */ | ||
| const emittedPackageWarnings = new Set(); | ||
| const doubleSlashRegEx = /[/\\]{2}/; | ||
| /** | ||
| * | ||
| * @param {string} target | ||
| * @param {string} request | ||
| * @param {string} match | ||
| * @param {URL} packageJsonUrl | ||
| * @param {boolean} internal | ||
| * @param {URL} base | ||
| * @param {boolean} isTarget | ||
| */ | ||
| function emitInvalidSegmentDeprecation( | ||
| target, | ||
| request, | ||
| match, | ||
| packageJsonUrl, | ||
| internal, | ||
| base, | ||
| isTarget | ||
| ) { | ||
| // @ts-expect-error: apparently it does exist, TS. | ||
| if (process$1.noDeprecation) { | ||
| return | ||
| } | ||
| const pjsonPath = fileURLToPath$1(packageJsonUrl); | ||
| const double = doubleSlashRegEx.exec(isTarget ? target : request) !== null; | ||
| process$1.emitWarning( | ||
| `Use of deprecated ${ | ||
| double ? 'double slash' : 'leading or trailing slash matching' | ||
| } resolving "${target}" for module ` + | ||
| `request "${request}" ${ | ||
| request === match ? '' : `matched to "${match}" ` | ||
| }in the "${ | ||
| internal ? 'imports' : 'exports' | ||
| }" field module resolution of the package at ${pjsonPath}${ | ||
| base ? ` imported from ${fileURLToPath$1(base)}` : '' | ||
| }.`, | ||
| 'DeprecationWarning', | ||
| 'DEP0166' | ||
| ); | ||
| } | ||
| /** | ||
| * @param {URL} url | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @param {string} [main] | ||
| * @returns {void} | ||
| */ | ||
| function emitLegacyIndexDeprecation(url, packageJsonUrl, base, main) { | ||
| // @ts-expect-error: apparently it does exist, TS. | ||
| if (process$1.noDeprecation) { | ||
| return | ||
| } | ||
| const format = defaultGetFormatWithoutErrors(url, {parentURL: base.href}); | ||
| if (format !== 'module') return | ||
| const urlPath = fileURLToPath$1(url.href); | ||
| const packagePath = fileURLToPath$1(new URL$1('.', packageJsonUrl)); | ||
| const basePath = fileURLToPath$1(base); | ||
| if (!main) { | ||
| process$1.emitWarning( | ||
| `No "main" or "exports" field defined in the package.json for ${packagePath} resolving the main entry point "${urlPath.slice( | ||
| packagePath.length | ||
| )}", imported from ${basePath}.\nDefault "index" lookups for the main are deprecated for ES modules.`, | ||
| 'DeprecationWarning', | ||
| 'DEP0151' | ||
| ); | ||
| } else if (path.resolve(packagePath, main) !== urlPath) { | ||
| process$1.emitWarning( | ||
| `Package ${packagePath} has a "main" field set to "${main}", ` + | ||
| `excluding the full filename and extension to the resolved file at "${urlPath.slice( | ||
| packagePath.length | ||
| )}", imported from ${basePath}.\n Automatic extension resolution of the "main" field is ` + | ||
| 'deprecated for ES modules.', | ||
| 'DeprecationWarning', | ||
| 'DEP0151' | ||
| ); | ||
| } | ||
| } | ||
| /** | ||
| * @param {string} path | ||
| * @returns {Stats | undefined} | ||
| */ | ||
| function tryStatSync(path) { | ||
| // Note: from Node 15 onwards we can use `throwIfNoEntry: false` instead. | ||
| try { | ||
| return statSync(path) | ||
| } catch { | ||
| // Note: in Node code this returns `new Stats`, | ||
| // but in Node 22 that’s marked as a deprecated internal API. | ||
| // Which, well, we kinda are, but still to prevent that warning, | ||
| // just yield `undefined`. | ||
| } | ||
| } | ||
| /** | ||
| * Legacy CommonJS main resolution: | ||
| * 1. let M = pkg_url + (json main field) | ||
| * 2. TRY(M, M.js, M.json, M.node) | ||
| * 3. TRY(M/index.js, M/index.json, M/index.node) | ||
| * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node) | ||
| * 5. NOT_FOUND | ||
| * | ||
| * @param {URL} url | ||
| * @returns {boolean} | ||
| */ | ||
| function fileExists(url) { | ||
| const stats = statSync(url, {throwIfNoEntry: false}); | ||
| const isFile = stats ? stats.isFile() : undefined; | ||
| return isFile === null || isFile === undefined ? false : isFile | ||
| } | ||
| /** | ||
| * @param {URL} packageJsonUrl | ||
| * @param {PackageConfig} packageConfig | ||
| * @param {URL} base | ||
| * @returns {URL} | ||
| */ | ||
| function legacyMainResolve(packageJsonUrl, packageConfig, base) { | ||
| /** @type {URL | undefined} */ | ||
| let guess; | ||
| if (packageConfig.main !== undefined) { | ||
| guess = new URL$1(packageConfig.main, packageJsonUrl); | ||
| // Note: fs check redundances will be handled by Descriptor cache here. | ||
| if (fileExists(guess)) return guess | ||
| const tries = [ | ||
| `./${packageConfig.main}.js`, | ||
| `./${packageConfig.main}.json`, | ||
| `./${packageConfig.main}.node`, | ||
| `./${packageConfig.main}/index.js`, | ||
| `./${packageConfig.main}/index.json`, | ||
| `./${packageConfig.main}/index.node` | ||
| ]; | ||
| let i = -1; | ||
| while (++i < tries.length) { | ||
| guess = new URL$1(tries[i], packageJsonUrl); | ||
| if (fileExists(guess)) break | ||
| guess = undefined; | ||
| } | ||
| if (guess) { | ||
| emitLegacyIndexDeprecation( | ||
| guess, | ||
| packageJsonUrl, | ||
| base, | ||
| packageConfig.main | ||
| ); | ||
| return guess | ||
| } | ||
| // Fallthrough. | ||
| } | ||
| const tries = ['./index.js', './index.json', './index.node']; | ||
| let i = -1; | ||
| while (++i < tries.length) { | ||
| guess = new URL$1(tries[i], packageJsonUrl); | ||
| if (fileExists(guess)) break | ||
| guess = undefined; | ||
| } | ||
| if (guess) { | ||
| emitLegacyIndexDeprecation(guess, packageJsonUrl, base, packageConfig.main); | ||
| return guess | ||
| } | ||
| // Not found. | ||
| throw new ERR_MODULE_NOT_FOUND( | ||
| fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {URL} resolved | ||
| * @param {URL} base | ||
| * @param {boolean} [preserveSymlinks] | ||
| * @returns {URL} | ||
| */ | ||
| function finalizeResolution(resolved, base, preserveSymlinks) { | ||
| if (encodedSeparatorRegEx.exec(resolved.pathname) !== null) { | ||
| throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| resolved.pathname, | ||
| 'must not include encoded "/" or "\\" characters', | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** @type {string} */ | ||
| let filePath; | ||
| try { | ||
| filePath = fileURLToPath$1(resolved); | ||
| } catch (error) { | ||
| const cause = /** @type {ErrnoException} */ (error); | ||
| Object.defineProperty(cause, 'input', {value: String(resolved)}); | ||
| Object.defineProperty(cause, 'module', {value: String(base)}); | ||
| throw cause | ||
| } | ||
| const stats = tryStatSync( | ||
| filePath.endsWith('/') ? filePath.slice(-1) : filePath | ||
| ); | ||
| if (stats && stats.isDirectory()) { | ||
| const error = new ERR_UNSUPPORTED_DIR_IMPORT(filePath, fileURLToPath$1(base)); | ||
| // @ts-expect-error Add this for `import.meta.resolve`. | ||
| error.url = String(resolved); | ||
| throw error | ||
| } | ||
| if (!stats || !stats.isFile()) { | ||
| const error = new ERR_MODULE_NOT_FOUND( | ||
| filePath || resolved.pathname, | ||
| base && fileURLToPath$1(base), | ||
| true | ||
| ); | ||
| // @ts-expect-error Add this for `import.meta.resolve`. | ||
| error.url = String(resolved); | ||
| throw error | ||
| } | ||
| { | ||
| const real = realpathSync(filePath); | ||
| const {search, hash} = resolved; | ||
| resolved = pathToFileURL$1(real + (filePath.endsWith(path.sep) ? '/' : '')); | ||
| resolved.search = search; | ||
| resolved.hash = hash; | ||
| } | ||
| return resolved | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {URL | undefined} packageJsonUrl | ||
| * @param {URL} base | ||
| * @returns {Error} | ||
| */ | ||
| function importNotDefined(specifier, packageJsonUrl, base) { | ||
| return new ERR_PACKAGE_IMPORT_NOT_DEFINED( | ||
| specifier, | ||
| packageJsonUrl && fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} subpath | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @returns {Error} | ||
| */ | ||
| function exportsNotFound(subpath, packageJsonUrl, base) { | ||
| return new ERR_PACKAGE_PATH_NOT_EXPORTED( | ||
| fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| subpath, | ||
| base && fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} request | ||
| * @param {string} match | ||
| * @param {URL} packageJsonUrl | ||
| * @param {boolean} internal | ||
| * @param {URL} [base] | ||
| * @returns {never} | ||
| */ | ||
| function throwInvalidSubpath(request, match, packageJsonUrl, internal, base) { | ||
| const reason = `request is not a valid match in pattern "${match}" for the "${ | ||
| internal ? 'imports' : 'exports' | ||
| }" resolution of ${fileURLToPath$1(packageJsonUrl)}`; | ||
| throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| request, | ||
| reason, | ||
| base && fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} subpath | ||
| * @param {unknown} target | ||
| * @param {URL} packageJsonUrl | ||
| * @param {boolean} internal | ||
| * @param {URL} [base] | ||
| * @returns {Error} | ||
| */ | ||
| function invalidPackageTarget(subpath, target, packageJsonUrl, internal, base) { | ||
| target = | ||
| typeof target === 'object' && target !== null | ||
| ? JSON.stringify(target, null, '') | ||
| : `${target}`; | ||
| return new ERR_INVALID_PACKAGE_TARGET( | ||
| fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| subpath, | ||
| target, | ||
| internal, | ||
| base && fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} target | ||
| * @param {string} subpath | ||
| * @param {string} match | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @param {boolean} pattern | ||
| * @param {boolean} internal | ||
| * @param {boolean} isPathMap | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL} | ||
| */ | ||
| function resolvePackageTargetString( | ||
| target, | ||
| subpath, | ||
| match, | ||
| packageJsonUrl, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ) { | ||
| if (subpath !== '' && !pattern && target[target.length - 1] !== '/') | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| if (!target.startsWith('./')) { | ||
| if (internal && !target.startsWith('../') && !target.startsWith('/')) { | ||
| let isURL = false; | ||
| try { | ||
| new URL$1(target); | ||
| isURL = true; | ||
| } catch { | ||
| // Continue regardless of error. | ||
| } | ||
| if (!isURL) { | ||
| const exportTarget = pattern | ||
| ? RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| target, | ||
| () => subpath | ||
| ) | ||
| : target + subpath; | ||
| return packageResolve(exportTarget, packageJsonUrl, conditions) | ||
| } | ||
| } | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| } | ||
| if (invalidSegmentRegEx.exec(target.slice(2)) !== null) { | ||
| if (deprecatedInvalidSegmentRegEx.exec(target.slice(2)) === null) { | ||
| if (!isPathMap) { | ||
| const request = pattern | ||
| ? match.replace('*', () => subpath) | ||
| : match + subpath; | ||
| const resolvedTarget = pattern | ||
| ? RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| target, | ||
| () => subpath | ||
| ) | ||
| : target; | ||
| emitInvalidSegmentDeprecation( | ||
| resolvedTarget, | ||
| request, | ||
| match, | ||
| packageJsonUrl, | ||
| internal, | ||
| base, | ||
| true | ||
| ); | ||
| } | ||
| } else { | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| } | ||
| } | ||
| const resolved = new URL$1(target, packageJsonUrl); | ||
| const resolvedPath = resolved.pathname; | ||
| const packagePath = new URL$1('.', packageJsonUrl).pathname; | ||
| if (!resolvedPath.startsWith(packagePath)) | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| if (subpath === '') return resolved | ||
| if (invalidSegmentRegEx.exec(subpath) !== null) { | ||
| const request = pattern | ||
| ? match.replace('*', () => subpath) | ||
| : match + subpath; | ||
| if (deprecatedInvalidSegmentRegEx.exec(subpath) === null) { | ||
| if (!isPathMap) { | ||
| const resolvedTarget = pattern | ||
| ? RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| target, | ||
| () => subpath | ||
| ) | ||
| : target; | ||
| emitInvalidSegmentDeprecation( | ||
| resolvedTarget, | ||
| request, | ||
| match, | ||
| packageJsonUrl, | ||
| internal, | ||
| base, | ||
| false | ||
| ); | ||
| } | ||
| } else { | ||
| throwInvalidSubpath(request, match, packageJsonUrl, internal, base); | ||
| } | ||
| } | ||
| if (pattern) { | ||
| return new URL$1( | ||
| RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| resolved.href, | ||
| () => subpath | ||
| ) | ||
| ) | ||
| } | ||
| return new URL$1(subpath, resolved) | ||
| } | ||
| /** | ||
| * @param {string} key | ||
| * @returns {boolean} | ||
| */ | ||
| function isArrayIndex(key) { | ||
| const keyNumber = Number(key); | ||
| if (`${keyNumber}` !== key) return false | ||
| return keyNumber >= 0 && keyNumber < 0xff_ff_ff_ff | ||
| } | ||
| /** | ||
| * @param {URL} packageJsonUrl | ||
| * @param {unknown} target | ||
| * @param {string} subpath | ||
| * @param {string} packageSubpath | ||
| * @param {URL} base | ||
| * @param {boolean} pattern | ||
| * @param {boolean} internal | ||
| * @param {boolean} isPathMap | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL | null} | ||
| */ | ||
| function resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| subpath, | ||
| packageSubpath, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ) { | ||
| if (typeof target === 'string') { | ||
| return resolvePackageTargetString( | ||
| target, | ||
| subpath, | ||
| packageSubpath, | ||
| packageJsonUrl, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ) | ||
| } | ||
| if (Array.isArray(target)) { | ||
| /** @type {Array<unknown>} */ | ||
| const targetList = target; | ||
| if (targetList.length === 0) return null | ||
| /** @type {ErrnoException | null | undefined} */ | ||
| let lastException; | ||
| let i = -1; | ||
| while (++i < targetList.length) { | ||
| const targetItem = targetList[i]; | ||
| /** @type {URL | null} */ | ||
| let resolveResult; | ||
| try { | ||
| resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| targetItem, | ||
| subpath, | ||
| packageSubpath, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ); | ||
| } catch (error) { | ||
| const exception = /** @type {ErrnoException} */ (error); | ||
| lastException = exception; | ||
| if (exception.code === 'ERR_INVALID_PACKAGE_TARGET') continue | ||
| throw error | ||
| } | ||
| if (resolveResult === undefined) continue | ||
| if (resolveResult === null) { | ||
| lastException = null; | ||
| continue | ||
| } | ||
| return resolveResult | ||
| } | ||
| if (lastException === undefined || lastException === null) { | ||
| return null | ||
| } | ||
| throw lastException | ||
| } | ||
| if (typeof target === 'object' && target !== null) { | ||
| const keys = Object.getOwnPropertyNames(target); | ||
| let i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| if (isArrayIndex(key)) { | ||
| throw new ERR_INVALID_PACKAGE_CONFIG( | ||
| fileURLToPath$1(packageJsonUrl), | ||
| base, | ||
| '"exports" cannot contain numeric property keys.' | ||
| ) | ||
| } | ||
| } | ||
| i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| if (key === 'default' || (conditions && conditions.has(key))) { | ||
| // @ts-expect-error: indexable. | ||
| const conditionalTarget = /** @type {unknown} */ (target[key]); | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| conditionalTarget, | ||
| subpath, | ||
| packageSubpath, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ); | ||
| if (resolveResult === undefined) continue | ||
| return resolveResult | ||
| } | ||
| } | ||
| return null | ||
| } | ||
| if (target === null) { | ||
| return null | ||
| } | ||
| throw invalidPackageTarget( | ||
| packageSubpath, | ||
| target, | ||
| packageJsonUrl, | ||
| internal, | ||
| base | ||
| ) | ||
| } | ||
| /** | ||
| * @param {unknown} exports | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @returns {boolean} | ||
| */ | ||
| function isConditionalExportsMainSugar(exports$1, packageJsonUrl, base) { | ||
| if (typeof exports$1 === 'string' || Array.isArray(exports$1)) return true | ||
| if (typeof exports$1 !== 'object' || exports$1 === null) return false | ||
| const keys = Object.getOwnPropertyNames(exports$1); | ||
| let isConditionalSugar = false; | ||
| let i = 0; | ||
| let keyIndex = -1; | ||
| while (++keyIndex < keys.length) { | ||
| const key = keys[keyIndex]; | ||
| const currentIsConditionalSugar = key === '' || key[0] !== '.'; | ||
| if (i++ === 0) { | ||
| isConditionalSugar = currentIsConditionalSugar; | ||
| } else if (isConditionalSugar !== currentIsConditionalSugar) { | ||
| throw new ERR_INVALID_PACKAGE_CONFIG( | ||
| fileURLToPath$1(packageJsonUrl), | ||
| base, | ||
| '"exports" cannot contain some keys starting with \'.\' and some not.' + | ||
| ' The exports object must either be an object of package subpath keys' + | ||
| ' or an object of main entry condition name keys only.' | ||
| ) | ||
| } | ||
| } | ||
| return isConditionalSugar | ||
| } | ||
| /** | ||
| * @param {string} match | ||
| * @param {URL} pjsonUrl | ||
| * @param {URL} base | ||
| */ | ||
| function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) { | ||
| // @ts-expect-error: apparently it does exist, TS. | ||
| if (process$1.noDeprecation) { | ||
| return | ||
| } | ||
| const pjsonPath = fileURLToPath$1(pjsonUrl); | ||
| if (emittedPackageWarnings.has(pjsonPath + '|' + match)) return | ||
| emittedPackageWarnings.add(pjsonPath + '|' + match); | ||
| process$1.emitWarning( | ||
| `Use of deprecated trailing slash pattern mapping "${match}" in the ` + | ||
| `"exports" field module resolution of the package at ${pjsonPath}${ | ||
| base ? ` imported from ${fileURLToPath$1(base)}` : '' | ||
| }. Mapping specifiers ending in "/" is no longer supported.`, | ||
| 'DeprecationWarning', | ||
| 'DEP0155' | ||
| ); | ||
| } | ||
| /** | ||
| * @param {URL} packageJsonUrl | ||
| * @param {string} packageSubpath | ||
| * @param {Record<string, unknown>} packageConfig | ||
| * @param {URL} base | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL} | ||
| */ | ||
| function packageExportsResolve( | ||
| packageJsonUrl, | ||
| packageSubpath, | ||
| packageConfig, | ||
| base, | ||
| conditions | ||
| ) { | ||
| let exports$1 = packageConfig.exports; | ||
| if (isConditionalExportsMainSugar(exports$1, packageJsonUrl, base)) { | ||
| exports$1 = {'.': exports$1}; | ||
| } | ||
| if ( | ||
| own.call(exports$1, packageSubpath) && | ||
| !packageSubpath.includes('*') && | ||
| !packageSubpath.endsWith('/') | ||
| ) { | ||
| // @ts-expect-error: indexable. | ||
| const target = exports$1[packageSubpath]; | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| '', | ||
| packageSubpath, | ||
| base, | ||
| false, | ||
| false, | ||
| false, | ||
| conditions | ||
| ); | ||
| if (resolveResult === null || resolveResult === undefined) { | ||
| throw exportsNotFound(packageSubpath, packageJsonUrl, base) | ||
| } | ||
| return resolveResult | ||
| } | ||
| let bestMatch = ''; | ||
| let bestMatchSubpath = ''; | ||
| const keys = Object.getOwnPropertyNames(exports$1); | ||
| let i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| const patternIndex = key.indexOf('*'); | ||
| if ( | ||
| patternIndex !== -1 && | ||
| packageSubpath.startsWith(key.slice(0, patternIndex)) | ||
| ) { | ||
| // When this reaches EOL, this can throw at the top of the whole function: | ||
| // | ||
| // if (StringPrototypeEndsWith(packageSubpath, '/')) | ||
| // throwInvalidSubpath(packageSubpath) | ||
| // | ||
| // To match "imports" and the spec. | ||
| if (packageSubpath.endsWith('/')) { | ||
| emitTrailingSlashPatternDeprecation( | ||
| packageSubpath, | ||
| packageJsonUrl, | ||
| base | ||
| ); | ||
| } | ||
| const patternTrailer = key.slice(patternIndex + 1); | ||
| if ( | ||
| packageSubpath.length >= key.length && | ||
| packageSubpath.endsWith(patternTrailer) && | ||
| patternKeyCompare(bestMatch, key) === 1 && | ||
| key.lastIndexOf('*') === patternIndex | ||
| ) { | ||
| bestMatch = key; | ||
| bestMatchSubpath = packageSubpath.slice( | ||
| patternIndex, | ||
| packageSubpath.length - patternTrailer.length | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| if (bestMatch) { | ||
| // @ts-expect-error: indexable. | ||
| const target = /** @type {unknown} */ (exports$1[bestMatch]); | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| bestMatchSubpath, | ||
| bestMatch, | ||
| base, | ||
| true, | ||
| false, | ||
| packageSubpath.endsWith('/'), | ||
| conditions | ||
| ); | ||
| if (resolveResult === null || resolveResult === undefined) { | ||
| throw exportsNotFound(packageSubpath, packageJsonUrl, base) | ||
| } | ||
| return resolveResult | ||
| } | ||
| throw exportsNotFound(packageSubpath, packageJsonUrl, base) | ||
| } | ||
| /** | ||
| * @param {string} a | ||
| * @param {string} b | ||
| */ | ||
| function patternKeyCompare(a, b) { | ||
| const aPatternIndex = a.indexOf('*'); | ||
| const bPatternIndex = b.indexOf('*'); | ||
| const baseLengthA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; | ||
| const baseLengthB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; | ||
| if (baseLengthA > baseLengthB) return -1 | ||
| if (baseLengthB > baseLengthA) return 1 | ||
| if (aPatternIndex === -1) return 1 | ||
| if (bPatternIndex === -1) return -1 | ||
| if (a.length > b.length) return -1 | ||
| if (b.length > a.length) return 1 | ||
| return 0 | ||
| } | ||
| /** | ||
| * @param {string} name | ||
| * @param {URL} base | ||
| * @param {Set<string>} [conditions] | ||
| * @returns {URL} | ||
| */ | ||
| function packageImportsResolve(name, base, conditions) { | ||
| if (name === '#' || name.startsWith('#/') || name.endsWith('/')) { | ||
| const reason = 'is not a valid internal imports specifier name'; | ||
| throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath$1(base)) | ||
| } | ||
| /** @type {URL | undefined} */ | ||
| let packageJsonUrl; | ||
| const packageConfig = getPackageScopeConfig(base); | ||
| if (packageConfig.exists) { | ||
| packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath); | ||
| const imports = packageConfig.imports; | ||
| if (imports) { | ||
| if (own.call(imports, name) && !name.includes('*')) { | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| imports[name], | ||
| '', | ||
| name, | ||
| base, | ||
| false, | ||
| true, | ||
| false, | ||
| conditions | ||
| ); | ||
| if (resolveResult !== null && resolveResult !== undefined) { | ||
| return resolveResult | ||
| } | ||
| } else { | ||
| let bestMatch = ''; | ||
| let bestMatchSubpath = ''; | ||
| const keys = Object.getOwnPropertyNames(imports); | ||
| let i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| const patternIndex = key.indexOf('*'); | ||
| if (patternIndex !== -1 && name.startsWith(key.slice(0, -1))) { | ||
| const patternTrailer = key.slice(patternIndex + 1); | ||
| if ( | ||
| name.length >= key.length && | ||
| name.endsWith(patternTrailer) && | ||
| patternKeyCompare(bestMatch, key) === 1 && | ||
| key.lastIndexOf('*') === patternIndex | ||
| ) { | ||
| bestMatch = key; | ||
| bestMatchSubpath = name.slice( | ||
| patternIndex, | ||
| name.length - patternTrailer.length | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| if (bestMatch) { | ||
| const target = imports[bestMatch]; | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| bestMatchSubpath, | ||
| bestMatch, | ||
| base, | ||
| true, | ||
| true, | ||
| false, | ||
| conditions | ||
| ); | ||
| if (resolveResult !== null && resolveResult !== undefined) { | ||
| return resolveResult | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| throw importNotDefined(name, packageJsonUrl, base) | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {URL} base | ||
| */ | ||
| function parsePackageName(specifier, base) { | ||
| let separatorIndex = specifier.indexOf('/'); | ||
| let validPackageName = true; | ||
| let isScoped = false; | ||
| if (specifier[0] === '@') { | ||
| isScoped = true; | ||
| if (separatorIndex === -1 || specifier.length === 0) { | ||
| validPackageName = false; | ||
| } else { | ||
| separatorIndex = specifier.indexOf('/', separatorIndex + 1); | ||
| } | ||
| } | ||
| const packageName = | ||
| separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex); | ||
| // Package name cannot have leading . and cannot have percent-encoding or | ||
| // \\ separators. | ||
| if (invalidPackageNameRegEx.exec(packageName) !== null) { | ||
| validPackageName = false; | ||
| } | ||
| if (!validPackageName) { | ||
| throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| specifier, | ||
| 'is not a valid package name', | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| const packageSubpath = | ||
| '.' + (separatorIndex === -1 ? '' : specifier.slice(separatorIndex)); | ||
| return {packageName, packageSubpath, isScoped} | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {URL} base | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL} | ||
| */ | ||
| function packageResolve(specifier, base, conditions) { | ||
| if (builtinModules.includes(specifier)) { | ||
| return new URL$1('node:' + specifier) | ||
| } | ||
| const {packageName, packageSubpath, isScoped} = parsePackageName( | ||
| specifier, | ||
| base | ||
| ); | ||
| // ResolveSelf | ||
| const packageConfig = getPackageScopeConfig(base); | ||
| // Can’t test. | ||
| /* c8 ignore next 16 */ | ||
| if (packageConfig.exists) { | ||
| const packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath); | ||
| if ( | ||
| packageConfig.name === packageName && | ||
| packageConfig.exports !== undefined && | ||
| packageConfig.exports !== null | ||
| ) { | ||
| return packageExportsResolve( | ||
| packageJsonUrl, | ||
| packageSubpath, | ||
| packageConfig, | ||
| base, | ||
| conditions | ||
| ) | ||
| } | ||
| } | ||
| let packageJsonUrl = new URL$1( | ||
| './node_modules/' + packageName + '/package.json', | ||
| base | ||
| ); | ||
| let packageJsonPath = fileURLToPath$1(packageJsonUrl); | ||
| /** @type {string} */ | ||
| let lastPath; | ||
| do { | ||
| const stat = tryStatSync(packageJsonPath.slice(0, -13)); | ||
| if (!stat || !stat.isDirectory()) { | ||
| lastPath = packageJsonPath; | ||
| packageJsonUrl = new URL$1( | ||
| (isScoped ? '../../../../node_modules/' : '../../../node_modules/') + | ||
| packageName + | ||
| '/package.json', | ||
| packageJsonUrl | ||
| ); | ||
| packageJsonPath = fileURLToPath$1(packageJsonUrl); | ||
| continue | ||
| } | ||
| // Package match. | ||
| const packageConfig = read(packageJsonPath, {base, specifier}); | ||
| if (packageConfig.exports !== undefined && packageConfig.exports !== null) { | ||
| return packageExportsResolve( | ||
| packageJsonUrl, | ||
| packageSubpath, | ||
| packageConfig, | ||
| base, | ||
| conditions | ||
| ) | ||
| } | ||
| if (packageSubpath === '.') { | ||
| return legacyMainResolve(packageJsonUrl, packageConfig, base) | ||
| } | ||
| return new URL$1(packageSubpath, packageJsonUrl) | ||
| // Cross-platform root check. | ||
| } while (packageJsonPath.length !== lastPath.length) | ||
| throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath$1(base), false) | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @returns {boolean} | ||
| */ | ||
| function isRelativeSpecifier(specifier) { | ||
| if (specifier[0] === '.') { | ||
| if (specifier.length === 1 || specifier[1] === '/') return true | ||
| if ( | ||
| specifier[1] === '.' && | ||
| (specifier.length === 2 || specifier[2] === '/') | ||
| ) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @returns {boolean} | ||
| */ | ||
| function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) { | ||
| if (specifier === '') return false | ||
| if (specifier[0] === '/') return true | ||
| return isRelativeSpecifier(specifier) | ||
| } | ||
| /** | ||
| * The “Resolver Algorithm Specification” as detailed in the Node docs (which is | ||
| * sync and slightly lower-level than `resolve`). | ||
| * | ||
| * @param {string} specifier | ||
| * `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc. | ||
| * @param {URL} base | ||
| * Full URL (to a file) that `specifier` is resolved relative from. | ||
| * @param {Set<string>} [conditions] | ||
| * Conditions. | ||
| * @param {boolean} [preserveSymlinks] | ||
| * Keep symlinks instead of resolving them. | ||
| * @returns {URL} | ||
| * A URL object to the found thing. | ||
| */ | ||
| function moduleResolve(specifier, base, conditions, preserveSymlinks) { | ||
| // Note: The Node code supports `base` as a string (in this internal API) too, | ||
| // we don’t. | ||
| const protocol = base.protocol; | ||
| const isData = protocol === 'data:'; | ||
| const isRemote = isData || protocol === 'http:' || protocol === 'https:'; | ||
| // Order swapped from spec for minor perf gain. | ||
| // Ok since relative URLs cannot parse as URLs. | ||
| /** @type {URL | undefined} */ | ||
| let resolved; | ||
| if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { | ||
| try { | ||
| resolved = new URL$1(specifier, base); | ||
| } catch (error_) { | ||
| const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base); | ||
| error.cause = error_; | ||
| throw error | ||
| } | ||
| } else if (protocol === 'file:' && specifier[0] === '#') { | ||
| resolved = packageImportsResolve(specifier, base, conditions); | ||
| } else { | ||
| try { | ||
| resolved = new URL$1(specifier); | ||
| } catch (error_) { | ||
| // Note: actual code uses `canBeRequiredWithoutScheme`. | ||
| if (isRemote && !builtinModules.includes(specifier)) { | ||
| const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base); | ||
| error.cause = error_; | ||
| throw error | ||
| } | ||
| resolved = packageResolve(specifier, base, conditions); | ||
| } | ||
| } | ||
| assert(resolved !== undefined, 'expected to be defined'); | ||
| if (resolved.protocol !== 'file:') { | ||
| return resolved | ||
| } | ||
| return finalizeResolution(resolved, base) | ||
| } | ||
| function fileURLToPath(id) { | ||
| if (typeof id === "string" && !id.startsWith("file://")) { | ||
| return normalizeSlash(id); | ||
| } | ||
| return normalizeSlash(fileURLToPath$1(id)); | ||
| } | ||
| function pathToFileURL(id) { | ||
| return pathToFileURL$1(fileURLToPath(id)).toString(); | ||
| } | ||
| function normalizeid(id) { | ||
| if (typeof id !== "string") { | ||
| id = id.toString(); | ||
| } | ||
| if (/(?:node|data|http|https|file):/.test(id)) { | ||
| return id; | ||
| } | ||
| if (BUILTIN_MODULES.has(id)) { | ||
| return "node:" + id; | ||
| } | ||
| return "file://" + encodeURI(normalizeSlash(id)); | ||
| } | ||
| const DEFAULT_CONDITIONS_SET = /* @__PURE__ */ new Set(["node", "import"]); | ||
| const DEFAULT_EXTENSIONS = [".mjs", ".cjs", ".js", ".json"]; | ||
| const NOT_FOUND_ERRORS = /* @__PURE__ */ new Set([ | ||
| "ERR_MODULE_NOT_FOUND", | ||
| "ERR_UNSUPPORTED_DIR_IMPORT", | ||
| "MODULE_NOT_FOUND", | ||
| "ERR_PACKAGE_PATH_NOT_EXPORTED" | ||
| ]); | ||
| function _tryModuleResolve(id, url, conditions) { | ||
| try { | ||
| return moduleResolve(id, url, conditions); | ||
| } catch (error) { | ||
| if (!NOT_FOUND_ERRORS.has(error?.code)) { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
| function _resolve$1(id, options = {}) { | ||
| if (typeof id !== "string") { | ||
| if (id instanceof URL) { | ||
| id = fileURLToPath(id); | ||
| } else { | ||
| throw new TypeError("input must be a `string` or `URL`"); | ||
| } | ||
| } | ||
| if (/(?:node|data|http|https):/.test(id)) { | ||
| return id; | ||
| } | ||
| if (BUILTIN_MODULES.has(id)) { | ||
| return "node:" + id; | ||
| } | ||
| if (id.startsWith("file://")) { | ||
| id = fileURLToPath(id); | ||
| } | ||
| if (isAbsolute(id)) { | ||
| try { | ||
| const stat = statSync(id); | ||
| if (stat.isFile()) { | ||
| return pathToFileURL(id); | ||
| } | ||
| } catch (error) { | ||
| if (error?.code !== "ENOENT") { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
| const conditionsSet = options.conditions ? new Set(options.conditions) : DEFAULT_CONDITIONS_SET; | ||
| const _urls = (Array.isArray(options.url) ? options.url : [options.url]).filter(Boolean).map((url) => new URL(normalizeid(url.toString()))); | ||
| if (_urls.length === 0) { | ||
| _urls.push(new URL(pathToFileURL(process.cwd()))); | ||
| } | ||
| const urls = [..._urls]; | ||
| for (const url of _urls) { | ||
| if (url.protocol === "file:") { | ||
| urls.push( | ||
| new URL("./", url), | ||
| // If url is directory | ||
| new URL(joinURL(url.pathname, "_index.js"), url), | ||
| // TODO: Remove in next major version? | ||
| new URL("node_modules", url) | ||
| ); | ||
| } | ||
| } | ||
| let resolved; | ||
| for (const url of urls) { | ||
| resolved = _tryModuleResolve(id, url, conditionsSet); | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| for (const prefix of ["", "/index"]) { | ||
| for (const extension of options.extensions || DEFAULT_EXTENSIONS) { | ||
| resolved = _tryModuleResolve( | ||
| joinURL(id, prefix) + extension, | ||
| url, | ||
| conditionsSet | ||
| ); | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| } | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| } | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| } | ||
| if (!resolved) { | ||
| const error = new Error( | ||
| `Cannot find module ${id} imported from ${urls.join(", ")}` | ||
| ); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| return pathToFileURL(resolved); | ||
| } | ||
| function resolveSync(id, options) { | ||
| return _resolve$1(id, options); | ||
| } | ||
| function resolvePathSync(id, options) { | ||
| return fileURLToPath(resolveSync(id, options)); | ||
| } | ||
| const GET_IS_ASYNC = Symbol.for("quansync.getIsAsync"); | ||
| class QuansyncError extends Error { | ||
| constructor(message = "Unexpected promise in sync context") { | ||
| super(message); | ||
| this.name = "QuansyncError"; | ||
| } | ||
| } | ||
| function isThenable(value) { | ||
| return value && typeof value === "object" && typeof value.then === "function"; | ||
| } | ||
| function isQuansyncGenerator(value) { | ||
| return value && typeof value === "object" && typeof value[Symbol.iterator] === "function" && "__quansync" in value; | ||
| } | ||
| function fromObject(options) { | ||
| const generator = function* (...args) { | ||
| const isAsync = yield GET_IS_ASYNC; | ||
| if (isAsync) | ||
| return yield options.async.apply(this, args); | ||
| return options.sync.apply(this, args); | ||
| }; | ||
| function fn(...args) { | ||
| const iter = generator.apply(this, args); | ||
| iter.then = (...thenArgs) => options.async.apply(this, args).then(...thenArgs); | ||
| iter.__quansync = true; | ||
| return iter; | ||
| } | ||
| fn.sync = options.sync; | ||
| fn.async = options.async; | ||
| return fn; | ||
| } | ||
| function fromPromise(promise) { | ||
| return fromObject({ | ||
| async: () => Promise.resolve(promise), | ||
| sync: () => { | ||
| if (isThenable(promise)) | ||
| throw new QuansyncError(); | ||
| return promise; | ||
| } | ||
| }); | ||
| } | ||
| function unwrapYield(value, isAsync) { | ||
| if (value === GET_IS_ASYNC) | ||
| return isAsync; | ||
| if (isQuansyncGenerator(value)) | ||
| return isAsync ? iterateAsync(value) : iterateSync(value); | ||
| if (!isAsync && isThenable(value)) | ||
| throw new QuansyncError(); | ||
| return value; | ||
| } | ||
| const DEFAULT_ON_YIELD = (value) => value; | ||
| function iterateSync(generator, onYield = DEFAULT_ON_YIELD) { | ||
| let current = generator.next(); | ||
| while (!current.done) { | ||
| try { | ||
| current = generator.next(unwrapYield(onYield(current.value, false))); | ||
| } catch (err) { | ||
| current = generator.throw(err); | ||
| } | ||
| } | ||
| return unwrapYield(current.value); | ||
| } | ||
| async function iterateAsync(generator, onYield = DEFAULT_ON_YIELD) { | ||
| let current = generator.next(); | ||
| while (!current.done) { | ||
| try { | ||
| current = generator.next(await unwrapYield(onYield(current.value, true), true)); | ||
| } catch (err) { | ||
| current = generator.throw(err); | ||
| } | ||
| } | ||
| return current.value; | ||
| } | ||
| function fromGeneratorFn(generatorFn, options) { | ||
| return fromObject({ | ||
| name: generatorFn.name, | ||
| async(...args) { | ||
| return iterateAsync(generatorFn.apply(this, args), options?.onYield); | ||
| }, | ||
| sync(...args) { | ||
| return iterateSync(generatorFn.apply(this, args), options?.onYield); | ||
| } | ||
| }); | ||
| } | ||
| function quansync$1(input, options) { | ||
| if (isThenable(input)) | ||
| return fromPromise(input); | ||
| if (typeof input === "function") | ||
| return fromGeneratorFn(input, options); | ||
| else | ||
| return fromObject(input); | ||
| } | ||
| quansync$1({ | ||
| async: () => Promise.resolve(true), | ||
| sync: () => false | ||
| }); | ||
| const quansync = quansync$1; | ||
| const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath$1(urlOrPath) : urlOrPath; | ||
| async function findUp$1(name, { | ||
| cwd = process$1.cwd(), | ||
| type = 'file', | ||
| stopAt, | ||
| } = {}) { | ||
| let directory = path.resolve(toPath(cwd) ?? ''); | ||
| const {root} = path.parse(directory); | ||
| stopAt = path.resolve(directory, toPath(stopAt ?? root)); | ||
| const isAbsoluteName = path.isAbsolute(name); | ||
| while (directory) { | ||
| const filePath = isAbsoluteName ? name : path.join(directory, name); | ||
| try { | ||
| const stats = await fs.stat(filePath); // eslint-disable-line no-await-in-loop | ||
| if ((type === 'file' && stats.isFile()) || (type === 'directory' && stats.isDirectory())) { | ||
| return filePath; | ||
| } | ||
| } catch {} | ||
| if (directory === stopAt || directory === root) { | ||
| break; | ||
| } | ||
| directory = path.dirname(directory); | ||
| } | ||
| } | ||
| function findUpSync(name, { | ||
| cwd = process$1.cwd(), | ||
| type = 'file', | ||
| stopAt, | ||
| } = {}) { | ||
| let directory = path.resolve(toPath(cwd) ?? ''); | ||
| const {root} = path.parse(directory); | ||
| stopAt = path.resolve(directory, toPath(stopAt) ?? root); | ||
| const isAbsoluteName = path.isAbsolute(name); | ||
| while (directory) { | ||
| const filePath = isAbsoluteName ? name : path.join(directory, name); | ||
| try { | ||
| const stats = fs__default.statSync(filePath, {throwIfNoEntry: false}); | ||
| if ((type === 'file' && stats?.isFile()) || (type === 'directory' && stats?.isDirectory())) { | ||
| return filePath; | ||
| } | ||
| } catch {} | ||
| if (directory === stopAt || directory === root) { | ||
| break; | ||
| } | ||
| directory = path.dirname(directory); | ||
| } | ||
| } | ||
| function _resolve(path, options = {}) { | ||
| if (options.platform === "auto" || !options.platform) | ||
| options.platform = process$1.platform === "win32" ? "win32" : "posix"; | ||
| if (process$1.versions.pnp) { | ||
| const paths = options.paths || []; | ||
| if (paths.length === 0) | ||
| paths.push(process$1.cwd()); | ||
| const targetRequire = createRequire(import.meta.url); | ||
| try { | ||
| return targetRequire.resolve(path, { paths }); | ||
| } catch { | ||
| } | ||
| } | ||
| const modulePath = resolvePathSync(path, { | ||
| url: options.paths | ||
| }); | ||
| if (options.platform === "win32") | ||
| return win32.normalize(modulePath); | ||
| return modulePath; | ||
| } | ||
| function resolveModule(name, options = {}) { | ||
| try { | ||
| return _resolve(name, options); | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| function isPackageExists(name, options = {}) { | ||
| return !!resolvePackage(name, options); | ||
| } | ||
| function getPackageJsonPath(name, options = {}) { | ||
| const entry = resolvePackage(name, options); | ||
| if (!entry) | ||
| return; | ||
| return searchPackageJSON(entry); | ||
| } | ||
| const readFile = quansync({ | ||
| async: (id) => fs__default.promises.readFile(id, "utf8"), | ||
| sync: (id) => fs__default.readFileSync(id, "utf8") | ||
| }); | ||
| const getPackageInfo = quansync(function* (name, options = {}) { | ||
| const packageJsonPath = getPackageJsonPath(name, options); | ||
| if (!packageJsonPath) | ||
| return; | ||
| const packageJson = JSON.parse(yield readFile(packageJsonPath)); | ||
| return { | ||
| name, | ||
| version: packageJson.version, | ||
| rootPath: dirname(packageJsonPath), | ||
| packageJsonPath, | ||
| packageJson | ||
| }; | ||
| }); | ||
| getPackageInfo.sync; | ||
| function resolvePackage(name, options = {}) { | ||
| try { | ||
| return _resolve(`${name}/package.json`, options); | ||
| } catch { | ||
| } | ||
| try { | ||
| return _resolve(name, options); | ||
| } catch (e) { | ||
| if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ERR_MODULE_NOT_FOUND") | ||
| console.error(e); | ||
| return false; | ||
| } | ||
| } | ||
| function searchPackageJSON(dir) { | ||
| let packageJsonPath; | ||
| while (true) { | ||
| if (!dir) | ||
| return; | ||
| const newDir = dirname(dir); | ||
| if (newDir === dir) | ||
| return; | ||
| dir = newDir; | ||
| packageJsonPath = join(dir, "package.json"); | ||
| if (fs__default.existsSync(packageJsonPath)) | ||
| break; | ||
| } | ||
| return packageJsonPath; | ||
| } | ||
| const findUp = quansync({ | ||
| sync: findUpSync, | ||
| async: findUp$1 | ||
| }); | ||
| const loadPackageJSON = quansync(function* (cwd = process$1.cwd()) { | ||
| const path = yield findUp("package.json", { cwd }); | ||
| if (!path || !fs__default.existsSync(path)) | ||
| return null; | ||
| return JSON.parse(yield readFile(path)); | ||
| }); | ||
| loadPackageJSON.sync; | ||
| const isPackageListed = quansync(function* (name, cwd) { | ||
| const pkg = (yield loadPackageJSON(cwd)) || {}; | ||
| return name in (pkg.dependencies || {}) || name in (pkg.devDependencies || {}); | ||
| }); | ||
| isPackageListed.sync; | ||
| class NativeModuleRunner extends ModuleRunner { | ||
| /** | ||
| * @internal | ||
| */ | ||
| mocker; | ||
| constructor(root, mocker) { | ||
| super({ | ||
| hmr: false, | ||
| sourcemapInterceptor: false, | ||
| transport: { invoke() { | ||
| throw new Error("Unexpected `invoke`"); | ||
| } } | ||
| }); | ||
| this.root = root; | ||
| this.mocker = mocker; | ||
| if (mocker) Object.defineProperty(globalThis, "__vitest_mocker__", { | ||
| configurable: true, | ||
| writable: true, | ||
| value: mocker | ||
| }); | ||
| } | ||
| async import(moduleId) { | ||
| const path = resolveModule(moduleId, { paths: [this.root] }) ?? resolve(this.root, moduleId); | ||
| // resolveModule doesn't keep the query params, so we need to add them back | ||
| let queryParams = ""; | ||
| if (moduleId.includes("?") && !path.includes("?")) queryParams = moduleId.slice(moduleId.indexOf("?")); | ||
| return import(pathToFileURL$1(path + queryParams).toString()); | ||
| } | ||
| } | ||
| var nativeModuleRunner = /*#__PURE__*/Object.freeze({ | ||
| __proto__: null, | ||
| NativeModuleRunner: NativeModuleRunner | ||
| }); | ||
| export { NativeModuleRunner as N, isPackageExists as i, nativeModuleRunner as n, resolveModule as r }; |
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import { promises, existsSync } from 'node:fs'; | ||
| import { i as isAbsolute, r as resolve, d as dirname, j as join, b as basename } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| class NodeSnapshotEnvironment { | ||
| constructor(options = {}) { | ||
| this.options = options; | ||
| } | ||
| getVersion() { | ||
| return "1"; | ||
| } | ||
| getHeader() { | ||
| return `// Snapshot v${this.getVersion()}`; | ||
| } | ||
| async resolveRawPath(testPath, rawPath) { | ||
| return isAbsolute(rawPath) ? rawPath : resolve(dirname(testPath), rawPath); | ||
| } | ||
| async resolvePath(filepath) { | ||
| return join(join(dirname(filepath), this.options.snapshotsDirName ?? "__snapshots__"), `${basename(filepath)}.snap`); | ||
| } | ||
| async prepareDirectory(dirPath) { | ||
| await promises.mkdir(dirPath, { recursive: true }); | ||
| } | ||
| async saveSnapshotFile(filepath, snapshot) { | ||
| await promises.mkdir(dirname(filepath), { recursive: true }); | ||
| await promises.writeFile(filepath, snapshot, "utf-8"); | ||
| } | ||
| async readSnapshotFile(filepath) { | ||
| if (!existsSync(filepath)) return null; | ||
| return promises.readFile(filepath, "utf-8"); | ||
| } | ||
| async removeSnapshotFile(filepath) { | ||
| if (existsSync(filepath)) await promises.unlink(filepath); | ||
| } | ||
| } | ||
| class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment { | ||
| getHeader() { | ||
| return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html`; | ||
| } | ||
| resolvePath(filepath) { | ||
| return getWorkerState().rpc.resolveSnapshotPath(filepath); | ||
| } | ||
| } | ||
| export { VitestNodeSnapshotEnvironment }; |
| const lineSplitRE = /\r?\n/; | ||
| function positionToOffset(source, lineNumber, columnNumber) { | ||
| const lines = source.split(lineSplitRE); | ||
| const nl = /\r\n/.test(source) ? 2 : 1; | ||
| let start = 0; | ||
| if (lineNumber > lines.length) return source.length; | ||
| for (let i = 0; i < lineNumber - 1; i++) start += lines[i].length + nl; | ||
| return start + columnNumber; | ||
| } | ||
| function offsetToLineNumber(source, offset) { | ||
| if (offset > source.length) throw new Error(`offset is longer than source length! offset ${offset} > length ${source.length}`); | ||
| const lines = source.split(lineSplitRE); | ||
| const nl = /\r\n/.test(source) ? 2 : 1; | ||
| let counted = 0; | ||
| let line = 0; | ||
| for (; line < lines.length; line++) { | ||
| const lineLength = lines[line].length + nl; | ||
| if (counted + lineLength >= offset) break; | ||
| counted += lineLength; | ||
| } | ||
| return line + 1; | ||
| } | ||
| export { lineSplitRE as l, offsetToLineNumber as o, positionToOffset as p }; |
| // TODO: this is all copy pasted from Vite - can they expose a module that exports only constants? | ||
| const KNOWN_ASSET_TYPES = [ | ||
| "apng", | ||
| "bmp", | ||
| "png", | ||
| "jpe?g", | ||
| "jfif", | ||
| "pjpeg", | ||
| "pjp", | ||
| "gif", | ||
| "svg", | ||
| "ico", | ||
| "webp", | ||
| "avif", | ||
| "mp4", | ||
| "webm", | ||
| "ogg", | ||
| "mp3", | ||
| "wav", | ||
| "flac", | ||
| "aac", | ||
| "woff2?", | ||
| "eot", | ||
| "ttf", | ||
| "otf", | ||
| "webmanifest", | ||
| "pdf", | ||
| "txt" | ||
| ]; | ||
| const KNOWN_ASSET_RE = new RegExp(`\\.(${KNOWN_ASSET_TYPES.join("|")})$`); | ||
| const CSS_LANGS_RE = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/; | ||
| /** | ||
| * Prefix for resolved Ids that are not valid browser import specifiers | ||
| */ | ||
| const VALID_ID_PREFIX = `/@id/`; | ||
| /** | ||
| * Plugins that use 'virtual modules' (e.g. for helper functions), prefix the | ||
| * module ID with `\0`, a convention from the rollup ecosystem. | ||
| * This prevents other plugins from trying to process the id (like node resolution), | ||
| * and core features like sourcemaps can use this info to differentiate between | ||
| * virtual modules and regular files. | ||
| * `\0` is not a permitted char in import URLs so we have to replace them during | ||
| * import analysis. The id will be decoded back before entering the plugins pipeline. | ||
| * These encoded virtual ids are also prefixed by the VALID_ID_PREFIX, so virtual | ||
| * modules in the browser end up encoded as `/@id/__x00__{id}` | ||
| */ | ||
| const NULL_BYTE_PLACEHOLDER = `__x00__`; | ||
| /** | ||
| * 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 stackTrace = new Error(message).stack || ""; | ||
| Error.prepareStackTrace = prepareStackTrace; | ||
| Error.stackTraceLimit = limit; | ||
| return stackTrace; | ||
| } | ||
| function notNullish(v) { | ||
| return v != null; | ||
| } | ||
| function assertTypes(value, name, types) { | ||
| const receivedType = typeof value; | ||
| if (!types.includes(receivedType)) throw new TypeError(`${name} value must be ${types.join(" or ")}, received "${receivedType}"`); | ||
| } | ||
| function isPrimitive(value) { | ||
| return value === null || typeof value !== "function" && typeof value !== "object"; | ||
| } | ||
| function slash(path) { | ||
| return path.replace(/\\/g, "/"); | ||
| } | ||
| const postfixRE = /[?#].*$/; | ||
| function cleanUrl(url) { | ||
| return url.replace(postfixRE, ""); | ||
| } | ||
| function splitFileAndPostfix(path) { | ||
| const file = cleanUrl(path); | ||
| return { | ||
| file, | ||
| postfix: path.slice(file.length) | ||
| }; | ||
| } | ||
| const externalRE = /^(?:[a-z]+:)?\/\//; | ||
| const isExternalUrl = (url) => externalRE.test(url); | ||
| /** | ||
| * Prepend `/@id/` and replace null byte so the id is URL-safe. | ||
| * This is prepended to resolved ids that are not valid browser | ||
| * import specifiers by the importAnalysis plugin. | ||
| */ | ||
| function wrapId(id) { | ||
| return id.startsWith(VALID_ID_PREFIX) ? id : VALID_ID_PREFIX + id.replace("\0", NULL_BYTE_PLACEHOLDER); | ||
| } | ||
| /** | ||
| * Undo {@link wrapId}'s `/@id/` and null byte replacements. | ||
| */ | ||
| function unwrapId(id) { | ||
| return id.startsWith(VALID_ID_PREFIX) ? id.slice(VALID_ID_PREFIX.length).replace(NULL_BYTE_PLACEHOLDER, "\0") : id; | ||
| } | ||
| function withTrailingSlash(path) { | ||
| if (path.at(-1) !== "/") return `${path}/`; | ||
| return path; | ||
| } | ||
| function filterOutComments(s) { | ||
| const result = []; | ||
| let commentState = "none"; | ||
| for (let i = 0; i < s.length; ++i) if (commentState === "singleline") { | ||
| if (s[i] === "\n") commentState = "none"; | ||
| } else if (commentState === "multiline") { | ||
| if (s[i - 1] === "*" && s[i] === "/") commentState = "none"; | ||
| } else if (commentState === "none") if (s[i] === "/" && s[i + 1] === "/") commentState = "singleline"; | ||
| else if (s[i] === "/" && s[i + 1] === "*") { | ||
| commentState = "multiline"; | ||
| i += 2; | ||
| } else result.push(s[i]); | ||
| return result.join(""); | ||
| } | ||
| const bareImportRE = /^(?![a-z]:)[\w@](?!.*:\/\/)/i; | ||
| function isBareImport(id) { | ||
| return bareImportRE.test(id); | ||
| } | ||
| function toArray(array) { | ||
| array ??= []; | ||
| if (Array.isArray(array)) return array; | ||
| return [array]; | ||
| } | ||
| function isObject(item) { | ||
| return item != null && typeof item === "object" && !Array.isArray(item); | ||
| } | ||
| function isFinalObj(obj) { | ||
| return obj === Object.prototype || obj === Function.prototype || obj === RegExp.prototype; | ||
| } | ||
| function getType(value) { | ||
| return Object.prototype.toString.apply(value).slice(8, -1); | ||
| } | ||
| function collectOwnProperties(obj, collector) { | ||
| const collect = typeof collector === "function" ? collector : (key) => collector.add(key); | ||
| Object.getOwnPropertyNames(obj).forEach(collect); | ||
| Object.getOwnPropertySymbols(obj).forEach(collect); | ||
| } | ||
| function getOwnProperties(obj) { | ||
| const ownProps = /* @__PURE__ */ new Set(); | ||
| if (isFinalObj(obj)) return []; | ||
| collectOwnProperties(obj, ownProps); | ||
| return Array.from(ownProps); | ||
| } | ||
| const defaultCloneOptions = { forceWritable: false }; | ||
| function deepClone(val, options = defaultCloneOptions) { | ||
| return clone(val, /* @__PURE__ */ new WeakMap(), options); | ||
| } | ||
| function clone(val, seen, options = defaultCloneOptions) { | ||
| let k, out; | ||
| if (seen.has(val)) return seen.get(val); | ||
| if (Array.isArray(val)) { | ||
| out = Array.from({ length: k = val.length }); | ||
| seen.set(val, out); | ||
| while (k--) out[k] = clone(val[k], seen, options); | ||
| return out; | ||
| } | ||
| if (Object.prototype.toString.call(val) === "[object Object]") { | ||
| out = Object.create(Object.getPrototypeOf(val)); | ||
| seen.set(val, out); | ||
| // we don't need properties from prototype | ||
| const props = getOwnProperties(val); | ||
| for (const k of props) { | ||
| const descriptor = Object.getOwnPropertyDescriptor(val, k); | ||
| if (!descriptor) continue; | ||
| const cloned = clone(val[k], seen, options); | ||
| if (options.forceWritable) Object.defineProperty(out, k, { | ||
| enumerable: descriptor.enumerable, | ||
| configurable: true, | ||
| writable: true, | ||
| value: cloned | ||
| }); | ||
| else if ("get" in descriptor) Object.defineProperty(out, k, { | ||
| ...descriptor, | ||
| get() { | ||
| return cloned; | ||
| } | ||
| }); | ||
| else Object.defineProperty(out, k, { | ||
| ...descriptor, | ||
| value: cloned | ||
| }); | ||
| } | ||
| return out; | ||
| } | ||
| return val; | ||
| } | ||
| function noop() {} | ||
| function objectAttr(source, path, defaultValue = void 0) { | ||
| // a[3].b -> a.3.b | ||
| const paths = path.replace(/\[(\d+)\]/g, ".$1").split("."); | ||
| let result = source; | ||
| for (const p of paths) { | ||
| result = new Object(result)[p]; | ||
| if (result === void 0) return defaultValue; | ||
| } | ||
| return result; | ||
| } | ||
| function createDefer() { | ||
| let resolve = null; | ||
| let reject = null; | ||
| const p = new Promise((_resolve, _reject) => { | ||
| resolve = _resolve; | ||
| reject = _reject; | ||
| }); | ||
| p.resolve = resolve; | ||
| p.reject = reject; | ||
| return p; | ||
| } | ||
| /** | ||
| * If code starts with a function call, will return its last index, respecting arguments. | ||
| * This will return 25 - last ending character of toMatch ")" | ||
| * Also works with callbacks | ||
| * ``` | ||
| * toMatch({ test: '123' }); | ||
| * toBeAliased('123') | ||
| * ``` | ||
| */ | ||
| function getCallLastIndex(code) { | ||
| let charIndex = -1; | ||
| let inString = null; | ||
| let startedBracers = 0; | ||
| let endedBracers = 0; | ||
| let beforeChar = null; | ||
| while (charIndex <= code.length) { | ||
| beforeChar = code[charIndex]; | ||
| charIndex++; | ||
| const char = code[charIndex]; | ||
| if ((char === "\"" || char === "'" || char === "`") && beforeChar !== "\\") { | ||
| if (inString === char) inString = null; | ||
| else if (!inString) inString = char; | ||
| } | ||
| if (!inString) { | ||
| if (char === "(") startedBracers++; | ||
| if (char === ")") endedBracers++; | ||
| } | ||
| if (startedBracers && endedBracers && startedBracers === endedBracers) return charIndex; | ||
| } | ||
| return null; | ||
| } | ||
| function isNegativeNaN(val) { | ||
| if (!Number.isNaN(val)) return false; | ||
| const f64 = new Float64Array(1); | ||
| f64[0] = val; | ||
| return new Uint32Array(f64.buffer)[1] >>> 31 === 1; | ||
| } | ||
| function toString(v) { | ||
| return Object.prototype.toString.call(v); | ||
| } | ||
| function isPlainObject(val) { | ||
| return toString(val) === "[object Object]" && (!val.constructor || val.constructor.name === "Object"); | ||
| } | ||
| function isMergeableObject(item) { | ||
| return isPlainObject(item) && !Array.isArray(item); | ||
| } | ||
| function ordinal(i) { | ||
| const j = i % 10; | ||
| const k = i % 100; | ||
| if (j === 1 && k !== 11) return `${i}st`; | ||
| if (j === 2 && k !== 12) return `${i}nd`; | ||
| if (j === 3 && k !== 13) return `${i}rd`; | ||
| return `${i}th`; | ||
| } | ||
| /** | ||
| * Deep merge :P | ||
| * | ||
| * Will merge objects only if they are plain | ||
| * | ||
| * Do not merge types - it is very expensive and usually it's better to case a type here | ||
| */ | ||
| function deepMerge(target, ...sources) { | ||
| if (!sources.length) return target; | ||
| const source = sources.shift(); | ||
| if (source === void 0) return target; | ||
| if (isMergeableObject(target) && isMergeableObject(source)) Object.keys(source).forEach((key) => { | ||
| const _source = source; | ||
| if (isMergeableObject(_source[key])) { | ||
| if (!target[key]) target[key] = {}; | ||
| deepMerge(target[key], _source[key]); | ||
| } else target[key] = _source[key]; | ||
| }); | ||
| return deepMerge(target, ...sources); | ||
| } | ||
| function unique(array) { | ||
| return Array.from(new Set(array)); | ||
| } | ||
| function sanitizeFilePath(s) { | ||
| // eslint-disable-next-line no-control-regex | ||
| return s.replace(/[\x00-\x2C\x2E\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-"); | ||
| } | ||
| 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 _UNC_REGEX = /^[/\\]{2}/; | ||
| const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/; | ||
| const _DRIVE_LETTER_RE = /^[A-Za-z]:$/; | ||
| const _ROOT_FOLDER_RE = /^\/([A-Za-z]:)?$/; | ||
| const _EXTNAME_RE = /.(\.[^./]+|\.)$/; | ||
| const normalize = function(path) { | ||
| if (path.length === 0) { | ||
| return "."; | ||
| } | ||
| path = normalizeWindowsPath(path); | ||
| const isUNCPath = path.match(_UNC_REGEX); | ||
| const isPathAbsolute = isAbsolute(path); | ||
| const trailingSeparator = path[path.length - 1] === "/"; | ||
| path = normalizeString(path, !isPathAbsolute); | ||
| if (path.length === 0) { | ||
| if (isPathAbsolute) { | ||
| return "/"; | ||
| } | ||
| return trailingSeparator ? "./" : "."; | ||
| } | ||
| if (trailingSeparator) { | ||
| path += "/"; | ||
| } | ||
| if (_DRIVE_LETTER_RE.test(path)) { | ||
| path += "/"; | ||
| } | ||
| if (isUNCPath) { | ||
| if (!isPathAbsolute) { | ||
| return `//./${path}`; | ||
| } | ||
| return `//${path}`; | ||
| } | ||
| return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path; | ||
| }; | ||
| const join = function(...segments) { | ||
| let path = ""; | ||
| for (const seg of segments) { | ||
| if (!seg) { | ||
| continue; | ||
| } | ||
| if (path.length > 0) { | ||
| const pathTrailing = path[path.length - 1] === "/"; | ||
| const segLeading = seg[0] === "/"; | ||
| const both = pathTrailing && segLeading; | ||
| if (both) { | ||
| path += seg.slice(1); | ||
| } else { | ||
| path += pathTrailing || segLeading ? seg : `/${seg}`; | ||
| } | ||
| } else { | ||
| path += seg; | ||
| } | ||
| } | ||
| return normalize(path); | ||
| }; | ||
| 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 extname = function(p) { | ||
| if (p === "..") return ""; | ||
| const match = _EXTNAME_RE.exec(normalizeWindowsPath(p)); | ||
| return match && match[1] || ""; | ||
| }; | ||
| const relative = function(from, to) { | ||
| const _from = resolve(from).replace(_ROOT_FOLDER_RE, "$1").split("/"); | ||
| const _to = resolve(to).replace(_ROOT_FOLDER_RE, "$1").split("/"); | ||
| if (_to[0][1] === ":" && _from[0][1] === ":" && _from[0] !== _to[0]) { | ||
| return _to.join("/"); | ||
| } | ||
| const _fromCopy = [..._from]; | ||
| for (const segment of _fromCopy) { | ||
| if (_to[0] !== segment) { | ||
| break; | ||
| } | ||
| _from.shift(); | ||
| _to.shift(); | ||
| } | ||
| return [..._from.map(() => ".."), ..._to].join("/"); | ||
| }; | ||
| const dirname = function(p) { | ||
| const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1); | ||
| if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) { | ||
| segments[0] += "/"; | ||
| } | ||
| return segments.join("/") || (isAbsolute(p) ? "/" : "."); | ||
| }; | ||
| const basename = function(p, extension) { | ||
| const segments = normalizeWindowsPath(p).split("/"); | ||
| let lastSegment = ""; | ||
| for (let i = segments.length - 1; i >= 0; i--) { | ||
| const val = segments[i]; | ||
| if (val) { | ||
| lastSegment = val; | ||
| break; | ||
| } | ||
| } | ||
| return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment; | ||
| }; | ||
| export { unique as A, objectAttr as B, CSS_LANGS_RE as C, createSimpleStackTrace as D, getCallLastIndex as E, deepMerge as F, withTrailingSlash as G, wrapId as H, isExternalUrl as I, unwrapId as J, KNOWN_ASSET_TYPES as K, sanitizeFilePath as L, relative as a, basename as b, cleanUrl as c, dirname as d, createDefer as e, extname as f, getType as g, KNOWN_ASSET_RE as h, isAbsolute as i, join as j, splitFileAndPostfix as k, isBareImport as l, isPrimitive as m, normalize as n, notNullish as o, noop as p, deepClone as q, resolve as r, slash as s, toArray as t, getOwnProperties as u, isObject as v, filterOutComments as w, ordinal as x, assertTypes as y, isNegativeNaN as z }; |
Sorry, the diff of this file is too big to display
| import { p as plugins } from './index.DzTmMrSM.js'; | ||
| const serialize = (val, config, indentation, depth, refs, printer) => { | ||
| // Serialize a non-default name, even if config.printFunctionName is false. | ||
| const name = val.getMockName(); | ||
| const nameString = name === "vi.fn()" ? "" : ` ${name}`; | ||
| let callsString = ""; | ||
| if (val.mock.calls.length !== 0) { | ||
| const indentationNext = indentation + config.indent; | ||
| callsString = ` {${config.spacingOuter}${indentationNext}"calls": ${printer(val.mock.calls, config, indentationNext, depth, refs)}${config.min ? ", " : ","}${config.spacingOuter}${indentationNext}"results": ${printer(val.mock.results, config, indentationNext, depth, refs)}${config.min ? "" : ","}${config.spacingOuter}${indentation}}`; | ||
| } | ||
| return `[MockFunction${nameString}]${callsString}`; | ||
| }; | ||
| const test = (val) => val && !!val._isMockFunction; | ||
| const plugin = { | ||
| serialize, | ||
| test | ||
| }; | ||
| const { DOMCollection, DOMElement, Immutable, ReactElement, ReactTestComponent, AsymmetricMatcher } = plugins; | ||
| let PLUGINS = [ | ||
| ReactTestComponent, | ||
| ReactElement, | ||
| DOMElement, | ||
| DOMCollection, | ||
| Immutable, | ||
| AsymmetricMatcher, | ||
| plugin | ||
| ]; | ||
| function addSerializer(plugin) { | ||
| PLUGINS = [plugin].concat(PLUGINS); | ||
| } | ||
| function getSerializers() { | ||
| return PLUGINS; | ||
| } | ||
| export { addSerializer as a, getSerializers as g }; |
| import fs__default from 'node:fs'; | ||
| import { b as basename, j as join, d as dirname } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| const packageScopeTypeCache = /* @__PURE__ */ new Map(); | ||
| // mirrors LOOKUP_PACKAGE_SCOPE from the ESM resolution algorithm: | ||
| // the lookup stops at the first package.json and never crosses | ||
| // the "node_modules" boundary, so typeless dependencies don't | ||
| // inherit the `type` field of the user's project | ||
| function lookupPackageScopeType(directory) { | ||
| const visited = []; | ||
| let result = "none"; | ||
| let current = directory; | ||
| while (current) { | ||
| const cached = packageScopeTypeCache.get(current); | ||
| if (cached) { | ||
| result = cached; | ||
| break; | ||
| } | ||
| if (basename(current) === "node_modules") break; | ||
| visited.push(current); | ||
| const packageJsonPath = join(current, "package.json"); | ||
| if (tryStatSync(packageJsonPath)?.isFile()) { | ||
| try { | ||
| const packageJson = JSON.parse(stripBomTag(fs__default.readFileSync(packageJsonPath, "utf8"))); | ||
| if (packageJson.type === "module") result = "esm"; | ||
| else if (packageJson.type === "commonjs") result = "cjs"; | ||
| } catch {} | ||
| break; | ||
| } | ||
| const parent = dirname(current); | ||
| if (parent === current) break; | ||
| current = parent; | ||
| } | ||
| visited.forEach((dir) => packageScopeTypeCache.set(dir, result)); | ||
| return result; | ||
| } | ||
| function stripBomTag(content) { | ||
| if (content.charCodeAt(0) === 65279) return content.slice(1); | ||
| return content; | ||
| } | ||
| function tryStatSync(file) { | ||
| try { | ||
| // The "throwIfNoEntry" is a performance optimization for cases where the file does not exist | ||
| return fs__default.statSync(file, { throwIfNoEntry: false }); | ||
| } catch {} | ||
| } | ||
| export { lookupPackageScopeType as l }; |
| import { bt as FetchCachedFileSystemResult, bu as ResolveFunctionResult, U as UserConsoleLog, br as AsyncLeak, F as File, K as AfterSuiteRunMeta, aS as TestBenchmark, a as TestArtifact, b as TaskResultPack, c as TaskEventPack, B as CancelReason, aD as SnapshotResult, Q as BaselineData } from './config.d.DsC1jkby.js'; | ||
| import { FetchFunctionOptions, FetchResult } from 'vite/module-runner'; | ||
| interface OTELCarrier { | ||
| traceparent?: string; | ||
| tracestate?: string; | ||
| } | ||
| interface TracesOptions { | ||
| enabled: boolean; | ||
| watchMode?: boolean; | ||
| sdkPath?: string; | ||
| tracerName?: string; | ||
| } | ||
| declare class Traces { | ||
| #private; | ||
| constructor(options: TracesOptions); | ||
| isEnabled(): boolean; | ||
| } | ||
| declare class GetterTracker { | ||
| static EXPORTS_MAX_INVOCATIONS: number; | ||
| private invocations; | ||
| private excessiveInvocations; | ||
| createTracker(moduleId: string, defineExport: (name: string, getter: () => unknown) => void): (name: string, getter: () => unknown) => void; | ||
| resetInvocations(): void; | ||
| getExcessiveInvocations(): GetterTrackerExport[]; | ||
| } | ||
| interface GetterTrackerExport { | ||
| moduleId: string; | ||
| exportName: string; | ||
| } | ||
| interface RuntimeRPC { | ||
| fetch: (id: string, importer: string | undefined, environment: string, options?: FetchFunctionOptions, otelCarrier?: OTELCarrier) => Promise<FetchResult | FetchCachedFileSystemResult>; | ||
| resolve: (id: string, importer: string | undefined, environment: string) => Promise<ResolveFunctionResult | null>; | ||
| /** | ||
| * Returns the modules of the given test files' import graphs that the server | ||
| * has already processed, so a fresh worker can load them from disk without | ||
| * paying a `fetch` round-trip per module. | ||
| */ | ||
| fetchWarmModules: (environment: string, files: string[]) => Promise<Record<string, FetchResult | FetchCachedFileSystemResult>>; | ||
| /** | ||
| * Transforms the import graphs of the given test files ahead of the | ||
| * worker's own fetches. Fired by vm pool workers before their environment | ||
| * setup, so the server transforms modules while the worker is busy | ||
| * importing its environment package. | ||
| */ | ||
| prewarmModuleGraph: (environment: string, files: string[]) => Promise<void>; | ||
| transform: (id: string) => Promise<{ | ||
| code?: string; | ||
| }>; | ||
| onUserConsoleLog: (log: UserConsoleLog) => void; | ||
| onUnhandledError: (err: unknown, type: string) => void; | ||
| onAsyncLeaks: (leak: AsyncLeak[]) => void; | ||
| onQueued: (file: File) => void; | ||
| onCollected: (files: File[]) => Promise<void>; | ||
| onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void; | ||
| onTestBenchmark: (testId: string, bench: TestBenchmark) => void; | ||
| onTaskArtifactRecord: <Artifact extends TestArtifact>(testId: string, artifact: Artifact) => Promise<Artifact>; | ||
| onTaskUpdate: (pack: TaskResultPack[], events: TaskEventPack[]) => Promise<void>; | ||
| onCancel: (reason: CancelReason) => void; | ||
| getCountOfFailedTests: () => number; | ||
| snapshotSaved: (snapshot: SnapshotResult) => void; | ||
| resolveSnapshotPath: (testPath: string) => string; | ||
| readBenchmarkResult: (relativePath: string) => Promise<BaselineData | null>; | ||
| writeBenchmarkResult: (relativePath: string, data: BaselineData) => Promise<void>; | ||
| ensureModuleGraphEntry: (id: string, importer: string) => void; | ||
| } | ||
| interface RunnerRPC { | ||
| onCancel: (reason: CancelReason) => void; | ||
| } | ||
| export { GetterTracker as G, Traces as T }; | ||
| export type { OTELCarrier as O, RunnerRPC as R, RuntimeRPC as a }; |
| import { EvaluatedModules } from 'vite/module-runner'; | ||
| import { d as dirname, r as resolve } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { a as getSafeTimers } from './source-map.DZdIqpIJ.js'; | ||
| import { c as createBirpc } from './index.Chj8NDwU.js'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| /* Ported from https://github.com/boblauer/MockDate/blob/master/src/mockdate.ts */ | ||
| /* | ||
| The MIT License (MIT) | ||
| Copyright (c) 2014 Bob Lauer | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. | ||
| */ | ||
| const RealDate = Date; | ||
| let now = null; | ||
| class MockDate extends RealDate { | ||
| constructor(y, m, d, h, M, s, ms) { | ||
| super(); | ||
| let date; | ||
| switch (arguments.length) { | ||
| case 0: | ||
| if (now !== null) date = new RealDate(now.valueOf()); | ||
| else date = new RealDate(); | ||
| break; | ||
| case 1: | ||
| date = new RealDate(y); | ||
| break; | ||
| default: | ||
| d = typeof d === "undefined" ? 1 : d; | ||
| h = h || 0; | ||
| M = M || 0; | ||
| s = s || 0; | ||
| ms = ms || 0; | ||
| date = new RealDate(y, m, d, h, M, s, ms); | ||
| break; | ||
| } | ||
| Object.setPrototypeOf(date, MockDate.prototype); | ||
| return date; | ||
| } | ||
| } | ||
| MockDate.UTC = RealDate.UTC; | ||
| MockDate.now = function() { | ||
| return new MockDate().valueOf(); | ||
| }; | ||
| MockDate.parse = function(dateString) { | ||
| return RealDate.parse(dateString); | ||
| }; | ||
| MockDate.toString = function() { | ||
| return RealDate.toString(); | ||
| }; | ||
| function mockDate(date) { | ||
| const dateObj = new RealDate(date.valueOf()); | ||
| if (Number.isNaN(dateObj.getTime())) throw new TypeError(`mockdate: The time set is an invalid date: ${date}`); | ||
| // @ts-expect-error global | ||
| globalThis.Date = MockDate; | ||
| now = dateObj.valueOf(); | ||
| } | ||
| function resetDate() { | ||
| globalThis.Date = RealDate; | ||
| } | ||
| // TODO: this is not needed in Vite 7.2+ | ||
| class VitestEvaluatedModules extends EvaluatedModules { | ||
| getModuleSourceMapById(id) { | ||
| const map = super.getModuleSourceMapById(id); | ||
| if (map != null && !("_patched" in map)) { | ||
| map._patched = true; | ||
| const dir = dirname(map.url); | ||
| map.resolvedSources = (map.map.sources || []).map((s) => resolve(dir, s || "")); | ||
| } | ||
| return map; | ||
| } | ||
| } | ||
| const { get } = Reflect; | ||
| function withSafeTimers(fn) { | ||
| const { setTimeout, clearTimeout, nextTick, setImmediate, clearImmediate } = getSafeTimers(); | ||
| const currentSetTimeout = globalThis.setTimeout; | ||
| const currentClearTimeout = globalThis.clearTimeout; | ||
| const currentSetImmediate = globalThis.setImmediate; | ||
| const currentClearImmediate = globalThis.clearImmediate; | ||
| const currentNextTick = globalThis.process?.nextTick; | ||
| try { | ||
| globalThis.setTimeout = setTimeout; | ||
| globalThis.clearTimeout = clearTimeout; | ||
| if (setImmediate) globalThis.setImmediate = setImmediate; | ||
| if (clearImmediate) globalThis.clearImmediate = clearImmediate; | ||
| if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick; | ||
| return fn(); | ||
| } finally { | ||
| globalThis.setTimeout = currentSetTimeout; | ||
| globalThis.clearTimeout = currentClearTimeout; | ||
| globalThis.setImmediate = currentSetImmediate; | ||
| globalThis.clearImmediate = currentClearImmediate; | ||
| if (globalThis.process && nextTick) nextTick(() => { | ||
| globalThis.process.nextTick = currentNextTick; | ||
| }); | ||
| } | ||
| } | ||
| const promises = /* @__PURE__ */ new Set(); | ||
| async function rpcDone() { | ||
| if (!promises.size) return; | ||
| const awaitable = Array.from(promises); | ||
| return Promise.all(awaitable); | ||
| } | ||
| const onCancelCallbacks = []; | ||
| function onCancel(callback) { | ||
| onCancelCallbacks.push(callback); | ||
| } | ||
| function createRuntimeRpc(options) { | ||
| return createSafeRpc(createBirpc({ async onCancel(reason) { | ||
| await Promise.all(onCancelCallbacks.map((fn) => fn(reason))); | ||
| } }, { | ||
| eventNames: ["onCancel"], | ||
| timeout: -1, | ||
| ...options | ||
| })); | ||
| } | ||
| function createSafeRpc(rpc) { | ||
| return new Proxy(rpc, { get(target, p, handler) { | ||
| // keep $rejectPendingCalls as sync function | ||
| if (p === "$rejectPendingCalls") return rpc.$rejectPendingCalls; | ||
| const sendCall = get(target, p, handler); | ||
| const safeSendCall = (...args) => withSafeTimers(async () => { | ||
| const result = sendCall(...args); | ||
| promises.add(result); | ||
| try { | ||
| return await result; | ||
| } finally { | ||
| promises.delete(result); | ||
| } | ||
| }); | ||
| safeSendCall.asEvent = sendCall.asEvent; | ||
| return safeSendCall; | ||
| } }); | ||
| } | ||
| function rpc() { | ||
| const { rpc } = getWorkerState(); | ||
| return rpc; | ||
| } | ||
| export { RealDate as R, VitestEvaluatedModules as V, rpcDone as a, resetDate as b, createRuntimeRpc as c, mockDate as m, onCancel as o, rpc as r }; |
| import { s as setSafeTimers } from './source-map.DZdIqpIJ.js'; | ||
| import { a as addSerializer } from './plugins.CsoX-42X.js'; | ||
| let globalSetup = false; | ||
| async function setupCommonEnv(config) { | ||
| setupDefines(config); | ||
| if (globalSetup) return; | ||
| globalSetup = true; | ||
| setSafeTimers(); | ||
| if (config.globals) (await import('./globals.sd6Qutmc.js')).registerApiGlobally(); | ||
| } | ||
| function setupDefines(config) { | ||
| for (const key in config.defines) globalThis[key] = config.defines[key]; | ||
| } | ||
| function setupEnv(env, metaEnv) { | ||
| for (const key in env) metaEnv[key] = env[key]; | ||
| } | ||
| async function loadDiffConfig(config, moduleRunner) { | ||
| if (typeof config.diff === "object") return config.diff; | ||
| if (typeof config.diff !== "string") return; | ||
| const diffModule = await moduleRunner.import(config.diff); | ||
| if (diffModule && typeof diffModule.default === "object" && diffModule.default != null) return diffModule.default; | ||
| else throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`); | ||
| } | ||
| async function loadSnapshotSerializers(config, moduleRunner) { | ||
| const files = config.snapshotSerializers; | ||
| (await Promise.all(files.map(async (file) => { | ||
| const mo = await moduleRunner.import(file); | ||
| if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`); | ||
| const config = mo.default; | ||
| if (typeof config.test !== "function" || typeof config.serialize !== "function" && typeof config.print !== "function") throw new TypeError(`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`); | ||
| return config; | ||
| }))).forEach((serializer) => addSerializer(serializer)); | ||
| } | ||
| export { loadSnapshotSerializers as a, setupEnv as b, loadDiffConfig as l, setupCommonEnv as s }; |
Sorry, the diff of this file is too big to display
| import { r as resolve$1, m as isPrimitive, o as notNullish } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {}; | ||
| function getDefaultExportFromCjs(x) { | ||
| return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; | ||
| } | ||
| var build = {}; | ||
| var hasRequiredBuild; | ||
| function requireBuild () { | ||
| if (hasRequiredBuild) return build; | ||
| hasRequiredBuild = 1; | ||
| Object.defineProperty(build, '__esModule', { | ||
| value: true | ||
| }); | ||
| build.default = diffSequence; | ||
| /** | ||
| * Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE file in the root directory of this source tree. | ||
| * | ||
| */ | ||
| // This diff-sequences package implements the linear space variation in | ||
| // An O(ND) Difference Algorithm and Its Variations by Eugene W. Myers | ||
| // Relationship in notation between Myers paper and this package: | ||
| // A is a | ||
| // N is aLength, aEnd - aStart, and so on | ||
| // x is aIndex, aFirst, aLast, and so on | ||
| // B is b | ||
| // M is bLength, bEnd - bStart, and so on | ||
| // y is bIndex, bFirst, bLast, and so on | ||
| // Δ = N - M is negative of baDeltaLength = bLength - aLength | ||
| // D is d | ||
| // k is kF | ||
| // k + Δ is kF = kR - baDeltaLength | ||
| // V is aIndexesF or aIndexesR (see comment below about Indexes type) | ||
| // index intervals [1, N] and [1, M] are [0, aLength) and [0, bLength) | ||
| // starting point in forward direction (0, 0) is (-1, -1) | ||
| // starting point in reverse direction (N + 1, M + 1) is (aLength, bLength) | ||
| // The “edit graph” for sequences a and b corresponds to items: | ||
| // in a on the horizontal axis | ||
| // in b on the vertical axis | ||
| // | ||
| // Given a-coordinate of a point in a diagonal, you can compute b-coordinate. | ||
| // | ||
| // Forward diagonals kF: | ||
| // zero diagonal intersects top left corner | ||
| // positive diagonals intersect top edge | ||
| // negative diagonals insersect left edge | ||
| // | ||
| // Reverse diagonals kR: | ||
| // zero diagonal intersects bottom right corner | ||
| // positive diagonals intersect right edge | ||
| // negative diagonals intersect bottom edge | ||
| // The graph contains a directed acyclic graph of edges: | ||
| // horizontal: delete an item from a | ||
| // vertical: insert an item from b | ||
| // diagonal: common item in a and b | ||
| // | ||
| // The algorithm solves dual problems in the graph analogy: | ||
| // Find longest common subsequence: path with maximum number of diagonal edges | ||
| // Find shortest edit script: path with minimum number of non-diagonal edges | ||
| // Input callback function compares items at indexes in the sequences. | ||
| // Output callback function receives the number of adjacent items | ||
| // and starting indexes of each common subsequence. | ||
| // Either original functions or wrapped to swap indexes if graph is transposed. | ||
| // Indexes in sequence a of last point of forward or reverse paths in graph. | ||
| // Myers algorithm indexes by diagonal k which for negative is bad deopt in V8. | ||
| // This package indexes by iF and iR which are greater than or equal to zero. | ||
| // and also updates the index arrays in place to cut memory in half. | ||
| // kF = 2 * iF - d | ||
| // kR = d - 2 * iR | ||
| // Division of index intervals in sequences a and b at the middle change. | ||
| // Invariant: intervals do not have common items at the start or end. | ||
| const pkg = 'diff-sequences'; // for error messages | ||
| const NOT_YET_SET = 0; // small int instead of undefined to avoid deopt in V8 | ||
| // Return the number of common items that follow in forward direction. | ||
| // The length of what Myers paper calls a “snake” in a forward path. | ||
| const countCommonItemsF = (aIndex, aEnd, bIndex, bEnd, isCommon) => { | ||
| let nCommon = 0; | ||
| while (aIndex < aEnd && bIndex < bEnd && isCommon(aIndex, bIndex)) { | ||
| aIndex += 1; | ||
| bIndex += 1; | ||
| nCommon += 1; | ||
| } | ||
| return nCommon; | ||
| }; | ||
| // Return the number of common items that precede in reverse direction. | ||
| // The length of what Myers paper calls a “snake” in a reverse path. | ||
| const countCommonItemsR = (aStart, aIndex, bStart, bIndex, isCommon) => { | ||
| let nCommon = 0; | ||
| while (aStart <= aIndex && bStart <= bIndex && isCommon(aIndex, bIndex)) { | ||
| aIndex -= 1; | ||
| bIndex -= 1; | ||
| nCommon += 1; | ||
| } | ||
| return nCommon; | ||
| }; | ||
| // A simple function to extend forward paths from (d - 1) to d changes | ||
| // when forward and reverse paths cannot yet overlap. | ||
| const extendPathsF = ( | ||
| d, | ||
| aEnd, | ||
| bEnd, | ||
| bF, | ||
| isCommon, | ||
| aIndexesF, | ||
| iMaxF // return the value because optimization might decrease it | ||
| ) => { | ||
| // Unroll the first iteration. | ||
| let iF = 0; | ||
| let kF = -d; // kF = 2 * iF - d | ||
| let aFirst = aIndexesF[iF]; // in first iteration always insert | ||
| let aIndexPrev1 = aFirst; // prev value of [iF - 1] in next iteration | ||
| aIndexesF[iF] += countCommonItemsF( | ||
| aFirst + 1, | ||
| aEnd, | ||
| bF + aFirst - kF + 1, | ||
| bEnd, | ||
| isCommon | ||
| ); | ||
| // Optimization: skip diagonals in which paths cannot ever overlap. | ||
| const nF = d < iMaxF ? d : iMaxF; | ||
| // The diagonals kF are odd when d is odd and even when d is even. | ||
| for (iF += 1, kF += 2; iF <= nF; iF += 1, kF += 2) { | ||
| // To get first point of path segment, move one change in forward direction | ||
| // from last point of previous path segment in an adjacent diagonal. | ||
| // In last possible iteration when iF === d and kF === d always delete. | ||
| if (iF !== d && aIndexPrev1 < aIndexesF[iF]) { | ||
| aFirst = aIndexesF[iF]; // vertical to insert from b | ||
| } else { | ||
| aFirst = aIndexPrev1 + 1; // horizontal to delete from a | ||
| if (aEnd <= aFirst) { | ||
| // Optimization: delete moved past right of graph. | ||
| return iF - 1; | ||
| } | ||
| } | ||
| // To get last point of path segment, move along diagonal of common items. | ||
| aIndexPrev1 = aIndexesF[iF]; | ||
| aIndexesF[iF] = | ||
| aFirst + | ||
| countCommonItemsF(aFirst + 1, aEnd, bF + aFirst - kF + 1, bEnd, isCommon); | ||
| } | ||
| return iMaxF; | ||
| }; | ||
| // A simple function to extend reverse paths from (d - 1) to d changes | ||
| // when reverse and forward paths cannot yet overlap. | ||
| const extendPathsR = ( | ||
| d, | ||
| aStart, | ||
| bStart, | ||
| bR, | ||
| isCommon, | ||
| aIndexesR, | ||
| iMaxR // return the value because optimization might decrease it | ||
| ) => { | ||
| // Unroll the first iteration. | ||
| let iR = 0; | ||
| let kR = d; // kR = d - 2 * iR | ||
| let aFirst = aIndexesR[iR]; // in first iteration always insert | ||
| let aIndexPrev1 = aFirst; // prev value of [iR - 1] in next iteration | ||
| aIndexesR[iR] -= countCommonItemsR( | ||
| aStart, | ||
| aFirst - 1, | ||
| bStart, | ||
| bR + aFirst - kR - 1, | ||
| isCommon | ||
| ); | ||
| // Optimization: skip diagonals in which paths cannot ever overlap. | ||
| const nR = d < iMaxR ? d : iMaxR; | ||
| // The diagonals kR are odd when d is odd and even when d is even. | ||
| for (iR += 1, kR -= 2; iR <= nR; iR += 1, kR -= 2) { | ||
| // To get first point of path segment, move one change in reverse direction | ||
| // from last point of previous path segment in an adjacent diagonal. | ||
| // In last possible iteration when iR === d and kR === -d always delete. | ||
| if (iR !== d && aIndexesR[iR] < aIndexPrev1) { | ||
| aFirst = aIndexesR[iR]; // vertical to insert from b | ||
| } else { | ||
| aFirst = aIndexPrev1 - 1; // horizontal to delete from a | ||
| if (aFirst < aStart) { | ||
| // Optimization: delete moved past left of graph. | ||
| return iR - 1; | ||
| } | ||
| } | ||
| // To get last point of path segment, move along diagonal of common items. | ||
| aIndexPrev1 = aIndexesR[iR]; | ||
| aIndexesR[iR] = | ||
| aFirst - | ||
| countCommonItemsR( | ||
| aStart, | ||
| aFirst - 1, | ||
| bStart, | ||
| bR + aFirst - kR - 1, | ||
| isCommon | ||
| ); | ||
| } | ||
| return iMaxR; | ||
| }; | ||
| // A complete function to extend forward paths from (d - 1) to d changes. | ||
| // Return true if a path overlaps reverse path of (d - 1) changes in its diagonal. | ||
| const extendOverlappablePathsF = ( | ||
| d, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| isCommon, | ||
| aIndexesF, | ||
| iMaxF, | ||
| aIndexesR, | ||
| iMaxR, | ||
| division // update prop values if return true | ||
| ) => { | ||
| const bF = bStart - aStart; // bIndex = bF + aIndex - kF | ||
| const aLength = aEnd - aStart; | ||
| const bLength = bEnd - bStart; | ||
| const baDeltaLength = bLength - aLength; // kF = kR - baDeltaLength | ||
| // Range of diagonals in which forward and reverse paths might overlap. | ||
| const kMinOverlapF = -baDeltaLength - (d - 1); // -(d - 1) <= kR | ||
| const kMaxOverlapF = -baDeltaLength + (d - 1); // kR <= (d - 1) | ||
| let aIndexPrev1 = NOT_YET_SET; // prev value of [iF - 1] in next iteration | ||
| // Optimization: skip diagonals in which paths cannot ever overlap. | ||
| const nF = d < iMaxF ? d : iMaxF; | ||
| // The diagonals kF = 2 * iF - d are odd when d is odd and even when d is even. | ||
| for (let iF = 0, kF = -d; iF <= nF; iF += 1, kF += 2) { | ||
| // To get first point of path segment, move one change in forward direction | ||
| // from last point of previous path segment in an adjacent diagonal. | ||
| // In first iteration when iF === 0 and kF === -d always insert. | ||
| // In last possible iteration when iF === d and kF === d always delete. | ||
| const insert = iF === 0 || (iF !== d && aIndexPrev1 < aIndexesF[iF]); | ||
| const aLastPrev = insert ? aIndexesF[iF] : aIndexPrev1; | ||
| const aFirst = insert | ||
| ? aLastPrev // vertical to insert from b | ||
| : aLastPrev + 1; // horizontal to delete from a | ||
| // To get last point of path segment, move along diagonal of common items. | ||
| const bFirst = bF + aFirst - kF; | ||
| const nCommonF = countCommonItemsF( | ||
| aFirst + 1, | ||
| aEnd, | ||
| bFirst + 1, | ||
| bEnd, | ||
| isCommon | ||
| ); | ||
| const aLast = aFirst + nCommonF; | ||
| aIndexPrev1 = aIndexesF[iF]; | ||
| aIndexesF[iF] = aLast; | ||
| if (kMinOverlapF <= kF && kF <= kMaxOverlapF) { | ||
| // Solve for iR of reverse path with (d - 1) changes in diagonal kF: | ||
| // kR = kF + baDeltaLength | ||
| // kR = (d - 1) - 2 * iR | ||
| const iR = (d - 1 - (kF + baDeltaLength)) / 2; | ||
| // If this forward path overlaps the reverse path in this diagonal, | ||
| // then this is the middle change of the index intervals. | ||
| if (iR <= iMaxR && aIndexesR[iR] - 1 <= aLast) { | ||
| // Unlike the Myers algorithm which finds only the middle “snake” | ||
| // this package can find two common subsequences per division. | ||
| // Last point of previous path segment is on an adjacent diagonal. | ||
| const bLastPrev = bF + aLastPrev - (insert ? kF + 1 : kF - 1); | ||
| // Because of invariant that intervals preceding the middle change | ||
| // cannot have common items at the end, | ||
| // move in reverse direction along a diagonal of common items. | ||
| const nCommonR = countCommonItemsR( | ||
| aStart, | ||
| aLastPrev, | ||
| bStart, | ||
| bLastPrev, | ||
| isCommon | ||
| ); | ||
| const aIndexPrevFirst = aLastPrev - nCommonR; | ||
| const bIndexPrevFirst = bLastPrev - nCommonR; | ||
| const aEndPreceding = aIndexPrevFirst + 1; | ||
| const bEndPreceding = bIndexPrevFirst + 1; | ||
| division.nChangePreceding = d - 1; | ||
| if (d - 1 === aEndPreceding + bEndPreceding - aStart - bStart) { | ||
| // Optimization: number of preceding changes in forward direction | ||
| // is equal to number of items in preceding interval, | ||
| // therefore it cannot contain any common items. | ||
| division.aEndPreceding = aStart; | ||
| division.bEndPreceding = bStart; | ||
| } else { | ||
| division.aEndPreceding = aEndPreceding; | ||
| division.bEndPreceding = bEndPreceding; | ||
| } | ||
| division.nCommonPreceding = nCommonR; | ||
| if (nCommonR !== 0) { | ||
| division.aCommonPreceding = aEndPreceding; | ||
| division.bCommonPreceding = bEndPreceding; | ||
| } | ||
| division.nCommonFollowing = nCommonF; | ||
| if (nCommonF !== 0) { | ||
| division.aCommonFollowing = aFirst + 1; | ||
| division.bCommonFollowing = bFirst + 1; | ||
| } | ||
| const aStartFollowing = aLast + 1; | ||
| const bStartFollowing = bFirst + nCommonF + 1; | ||
| division.nChangeFollowing = d - 1; | ||
| if (d - 1 === aEnd + bEnd - aStartFollowing - bStartFollowing) { | ||
| // Optimization: number of changes in reverse direction | ||
| // is equal to number of items in following interval, | ||
| // therefore it cannot contain any common items. | ||
| division.aStartFollowing = aEnd; | ||
| division.bStartFollowing = bEnd; | ||
| } else { | ||
| division.aStartFollowing = aStartFollowing; | ||
| division.bStartFollowing = bStartFollowing; | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| return false; | ||
| }; | ||
| // A complete function to extend reverse paths from (d - 1) to d changes. | ||
| // Return true if a path overlaps forward path of d changes in its diagonal. | ||
| const extendOverlappablePathsR = ( | ||
| d, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| isCommon, | ||
| aIndexesF, | ||
| iMaxF, | ||
| aIndexesR, | ||
| iMaxR, | ||
| division // update prop values if return true | ||
| ) => { | ||
| const bR = bEnd - aEnd; // bIndex = bR + aIndex - kR | ||
| const aLength = aEnd - aStart; | ||
| const bLength = bEnd - bStart; | ||
| const baDeltaLength = bLength - aLength; // kR = kF + baDeltaLength | ||
| // Range of diagonals in which forward and reverse paths might overlap. | ||
| const kMinOverlapR = baDeltaLength - d; // -d <= kF | ||
| const kMaxOverlapR = baDeltaLength + d; // kF <= d | ||
| let aIndexPrev1 = NOT_YET_SET; // prev value of [iR - 1] in next iteration | ||
| // Optimization: skip diagonals in which paths cannot ever overlap. | ||
| const nR = d < iMaxR ? d : iMaxR; | ||
| // The diagonals kR = d - 2 * iR are odd when d is odd and even when d is even. | ||
| for (let iR = 0, kR = d; iR <= nR; iR += 1, kR -= 2) { | ||
| // To get first point of path segment, move one change in reverse direction | ||
| // from last point of previous path segment in an adjacent diagonal. | ||
| // In first iteration when iR === 0 and kR === d always insert. | ||
| // In last possible iteration when iR === d and kR === -d always delete. | ||
| const insert = iR === 0 || (iR !== d && aIndexesR[iR] < aIndexPrev1); | ||
| const aLastPrev = insert ? aIndexesR[iR] : aIndexPrev1; | ||
| const aFirst = insert | ||
| ? aLastPrev // vertical to insert from b | ||
| : aLastPrev - 1; // horizontal to delete from a | ||
| // To get last point of path segment, move along diagonal of common items. | ||
| const bFirst = bR + aFirst - kR; | ||
| const nCommonR = countCommonItemsR( | ||
| aStart, | ||
| aFirst - 1, | ||
| bStart, | ||
| bFirst - 1, | ||
| isCommon | ||
| ); | ||
| const aLast = aFirst - nCommonR; | ||
| aIndexPrev1 = aIndexesR[iR]; | ||
| aIndexesR[iR] = aLast; | ||
| if (kMinOverlapR <= kR && kR <= kMaxOverlapR) { | ||
| // Solve for iF of forward path with d changes in diagonal kR: | ||
| // kF = kR - baDeltaLength | ||
| // kF = 2 * iF - d | ||
| const iF = (d + (kR - baDeltaLength)) / 2; | ||
| // If this reverse path overlaps the forward path in this diagonal, | ||
| // then this is a middle change of the index intervals. | ||
| if (iF <= iMaxF && aLast - 1 <= aIndexesF[iF]) { | ||
| const bLast = bFirst - nCommonR; | ||
| division.nChangePreceding = d; | ||
| if (d === aLast + bLast - aStart - bStart) { | ||
| // Optimization: number of changes in reverse direction | ||
| // is equal to number of items in preceding interval, | ||
| // therefore it cannot contain any common items. | ||
| division.aEndPreceding = aStart; | ||
| division.bEndPreceding = bStart; | ||
| } else { | ||
| division.aEndPreceding = aLast; | ||
| division.bEndPreceding = bLast; | ||
| } | ||
| division.nCommonPreceding = nCommonR; | ||
| if (nCommonR !== 0) { | ||
| // The last point of reverse path segment is start of common subsequence. | ||
| division.aCommonPreceding = aLast; | ||
| division.bCommonPreceding = bLast; | ||
| } | ||
| division.nChangeFollowing = d - 1; | ||
| if (d === 1) { | ||
| // There is no previous path segment. | ||
| division.nCommonFollowing = 0; | ||
| division.aStartFollowing = aEnd; | ||
| division.bStartFollowing = bEnd; | ||
| } else { | ||
| // Unlike the Myers algorithm which finds only the middle “snake” | ||
| // this package can find two common subsequences per division. | ||
| // Last point of previous path segment is on an adjacent diagonal. | ||
| const bLastPrev = bR + aLastPrev - (insert ? kR - 1 : kR + 1); | ||
| // Because of invariant that intervals following the middle change | ||
| // cannot have common items at the start, | ||
| // move in forward direction along a diagonal of common items. | ||
| const nCommonF = countCommonItemsF( | ||
| aLastPrev, | ||
| aEnd, | ||
| bLastPrev, | ||
| bEnd, | ||
| isCommon | ||
| ); | ||
| division.nCommonFollowing = nCommonF; | ||
| if (nCommonF !== 0) { | ||
| // The last point of reverse path segment is start of common subsequence. | ||
| division.aCommonFollowing = aLastPrev; | ||
| division.bCommonFollowing = bLastPrev; | ||
| } | ||
| const aStartFollowing = aLastPrev + nCommonF; // aFirstPrev | ||
| const bStartFollowing = bLastPrev + nCommonF; // bFirstPrev | ||
| if (d - 1 === aEnd + bEnd - aStartFollowing - bStartFollowing) { | ||
| // Optimization: number of changes in forward direction | ||
| // is equal to number of items in following interval, | ||
| // therefore it cannot contain any common items. | ||
| division.aStartFollowing = aEnd; | ||
| division.bStartFollowing = bEnd; | ||
| } else { | ||
| division.aStartFollowing = aStartFollowing; | ||
| division.bStartFollowing = bStartFollowing; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| return false; | ||
| }; | ||
| // Given index intervals and input function to compare items at indexes, | ||
| // divide at the middle change. | ||
| // | ||
| // DO NOT CALL if start === end, because interval cannot contain common items | ||
| // and because this function will throw the “no overlap” error. | ||
| const divide = ( | ||
| nChange, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| isCommon, | ||
| aIndexesF, | ||
| aIndexesR, | ||
| division // output | ||
| ) => { | ||
| const bF = bStart - aStart; // bIndex = bF + aIndex - kF | ||
| const bR = bEnd - aEnd; // bIndex = bR + aIndex - kR | ||
| const aLength = aEnd - aStart; | ||
| const bLength = bEnd - bStart; | ||
| // Because graph has square or portrait orientation, | ||
| // length difference is minimum number of items to insert from b. | ||
| // Corresponding forward and reverse diagonals in graph | ||
| // depend on length difference of the sequences: | ||
| // kF = kR - baDeltaLength | ||
| // kR = kF + baDeltaLength | ||
| const baDeltaLength = bLength - aLength; | ||
| // Optimization: max diagonal in graph intersects corner of shorter side. | ||
| let iMaxF = aLength; | ||
| let iMaxR = aLength; | ||
| // Initialize no changes yet in forward or reverse direction: | ||
| aIndexesF[0] = aStart - 1; // at open start of interval, outside closed start | ||
| aIndexesR[0] = aEnd; // at open end of interval | ||
| if (baDeltaLength % 2 === 0) { | ||
| // The number of changes in paths is 2 * d if length difference is even. | ||
| const dMin = (nChange || baDeltaLength) / 2; | ||
| const dMax = (aLength + bLength) / 2; | ||
| for (let d = 1; d <= dMax; d += 1) { | ||
| iMaxF = extendPathsF(d, aEnd, bEnd, bF, isCommon, aIndexesF, iMaxF); | ||
| if (d < dMin) { | ||
| iMaxR = extendPathsR(d, aStart, bStart, bR, isCommon, aIndexesR, iMaxR); | ||
| } else if ( | ||
| // If a reverse path overlaps a forward path in the same diagonal, | ||
| // return a division of the index intervals at the middle change. | ||
| extendOverlappablePathsR( | ||
| d, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| isCommon, | ||
| aIndexesF, | ||
| iMaxF, | ||
| aIndexesR, | ||
| iMaxR, | ||
| division | ||
| ) | ||
| ) { | ||
| return; | ||
| } | ||
| } | ||
| } else { | ||
| // The number of changes in paths is 2 * d - 1 if length difference is odd. | ||
| const dMin = ((nChange || baDeltaLength) + 1) / 2; | ||
| const dMax = (aLength + bLength + 1) / 2; | ||
| // Unroll first half iteration so loop extends the relevant pairs of paths. | ||
| // Because of invariant that intervals have no common items at start or end, | ||
| // and limitation not to call divide with empty intervals, | ||
| // therefore it cannot be called if a forward path with one change | ||
| // would overlap a reverse path with no changes, even if dMin === 1. | ||
| let d = 1; | ||
| iMaxF = extendPathsF(d, aEnd, bEnd, bF, isCommon, aIndexesF, iMaxF); | ||
| for (d += 1; d <= dMax; d += 1) { | ||
| iMaxR = extendPathsR( | ||
| d - 1, | ||
| aStart, | ||
| bStart, | ||
| bR, | ||
| isCommon, | ||
| aIndexesR, | ||
| iMaxR | ||
| ); | ||
| if (d < dMin) { | ||
| iMaxF = extendPathsF(d, aEnd, bEnd, bF, isCommon, aIndexesF, iMaxF); | ||
| } else if ( | ||
| // If a forward path overlaps a reverse path in the same diagonal, | ||
| // return a division of the index intervals at the middle change. | ||
| extendOverlappablePathsF( | ||
| d, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| isCommon, | ||
| aIndexesF, | ||
| iMaxF, | ||
| aIndexesR, | ||
| iMaxR, | ||
| division | ||
| ) | ||
| ) { | ||
| return; | ||
| } | ||
| } | ||
| } | ||
| /* istanbul ignore next */ | ||
| throw new Error( | ||
| `${pkg}: no overlap aStart=${aStart} aEnd=${aEnd} bStart=${bStart} bEnd=${bEnd}` | ||
| ); | ||
| }; | ||
| // Given index intervals and input function to compare items at indexes, | ||
| // return by output function the number of adjacent items and starting indexes | ||
| // of each common subsequence. Divide and conquer with only linear space. | ||
| // | ||
| // The index intervals are half open [start, end) like array slice method. | ||
| // DO NOT CALL if start === end, because interval cannot contain common items | ||
| // and because divide function will throw the “no overlap” error. | ||
| const findSubsequences = ( | ||
| nChange, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| transposed, | ||
| callbacks, | ||
| aIndexesF, | ||
| aIndexesR, | ||
| division // temporary memory, not input nor output | ||
| ) => { | ||
| if (bEnd - bStart < aEnd - aStart) { | ||
| // Transpose graph so it has portrait instead of landscape orientation. | ||
| // Always compare shorter to longer sequence for consistency and optimization. | ||
| transposed = !transposed; | ||
| if (transposed && callbacks.length === 1) { | ||
| // Lazily wrap callback functions to swap args if graph is transposed. | ||
| const {foundSubsequence, isCommon} = callbacks[0]; | ||
| callbacks[1] = { | ||
| foundSubsequence: (nCommon, bCommon, aCommon) => { | ||
| foundSubsequence(nCommon, aCommon, bCommon); | ||
| }, | ||
| isCommon: (bIndex, aIndex) => isCommon(aIndex, bIndex) | ||
| }; | ||
| } | ||
| const tStart = aStart; | ||
| const tEnd = aEnd; | ||
| aStart = bStart; | ||
| aEnd = bEnd; | ||
| bStart = tStart; | ||
| bEnd = tEnd; | ||
| } | ||
| const {foundSubsequence, isCommon} = callbacks[transposed ? 1 : 0]; | ||
| // Divide the index intervals at the middle change. | ||
| divide( | ||
| nChange, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| isCommon, | ||
| aIndexesF, | ||
| aIndexesR, | ||
| division | ||
| ); | ||
| const { | ||
| nChangePreceding, | ||
| aEndPreceding, | ||
| bEndPreceding, | ||
| nCommonPreceding, | ||
| aCommonPreceding, | ||
| bCommonPreceding, | ||
| nCommonFollowing, | ||
| aCommonFollowing, | ||
| bCommonFollowing, | ||
| nChangeFollowing, | ||
| aStartFollowing, | ||
| bStartFollowing | ||
| } = division; | ||
| // Unless either index interval is empty, they might contain common items. | ||
| if (aStart < aEndPreceding && bStart < bEndPreceding) { | ||
| // Recursely find and return common subsequences preceding the division. | ||
| findSubsequences( | ||
| nChangePreceding, | ||
| aStart, | ||
| aEndPreceding, | ||
| bStart, | ||
| bEndPreceding, | ||
| transposed, | ||
| callbacks, | ||
| aIndexesF, | ||
| aIndexesR, | ||
| division | ||
| ); | ||
| } | ||
| // Return common subsequences that are adjacent to the middle change. | ||
| if (nCommonPreceding !== 0) { | ||
| foundSubsequence(nCommonPreceding, aCommonPreceding, bCommonPreceding); | ||
| } | ||
| if (nCommonFollowing !== 0) { | ||
| foundSubsequence(nCommonFollowing, aCommonFollowing, bCommonFollowing); | ||
| } | ||
| // Unless either index interval is empty, they might contain common items. | ||
| if (aStartFollowing < aEnd && bStartFollowing < bEnd) { | ||
| // Recursely find and return common subsequences following the division. | ||
| findSubsequences( | ||
| nChangeFollowing, | ||
| aStartFollowing, | ||
| aEnd, | ||
| bStartFollowing, | ||
| bEnd, | ||
| transposed, | ||
| callbacks, | ||
| aIndexesF, | ||
| aIndexesR, | ||
| division | ||
| ); | ||
| } | ||
| }; | ||
| const validateLength = (name, arg) => { | ||
| if (typeof arg !== 'number') { | ||
| throw new TypeError(`${pkg}: ${name} typeof ${typeof arg} is not a number`); | ||
| } | ||
| if (!Number.isSafeInteger(arg)) { | ||
| throw new RangeError(`${pkg}: ${name} value ${arg} is not a safe integer`); | ||
| } | ||
| if (arg < 0) { | ||
| throw new RangeError(`${pkg}: ${name} value ${arg} is a negative integer`); | ||
| } | ||
| }; | ||
| const validateCallback = (name, arg) => { | ||
| const type = typeof arg; | ||
| if (type !== 'function') { | ||
| throw new TypeError(`${pkg}: ${name} typeof ${type} is not a function`); | ||
| } | ||
| }; | ||
| // Compare items in two sequences to find a longest common subsequence. | ||
| // Given lengths of sequences and input function to compare items at indexes, | ||
| // return by output function the number of adjacent items and starting indexes | ||
| // of each common subsequence. | ||
| function diffSequence(aLength, bLength, isCommon, foundSubsequence) { | ||
| validateLength('aLength', aLength); | ||
| validateLength('bLength', bLength); | ||
| validateCallback('isCommon', isCommon); | ||
| validateCallback('foundSubsequence', foundSubsequence); | ||
| // Count common items from the start in the forward direction. | ||
| const nCommonF = countCommonItemsF(0, aLength, 0, bLength, isCommon); | ||
| if (nCommonF !== 0) { | ||
| foundSubsequence(nCommonF, 0, 0); | ||
| } | ||
| // Unless both sequences consist of common items only, | ||
| // find common items in the half-trimmed index intervals. | ||
| if (aLength !== nCommonF || bLength !== nCommonF) { | ||
| // Invariant: intervals do not have common items at the start. | ||
| // The start of an index interval is closed like array slice method. | ||
| const aStart = nCommonF; | ||
| const bStart = nCommonF; | ||
| // Count common items from the end in the reverse direction. | ||
| const nCommonR = countCommonItemsR( | ||
| aStart, | ||
| aLength - 1, | ||
| bStart, | ||
| bLength - 1, | ||
| isCommon | ||
| ); | ||
| // Invariant: intervals do not have common items at the end. | ||
| // The end of an index interval is open like array slice method. | ||
| const aEnd = aLength - nCommonR; | ||
| const bEnd = bLength - nCommonR; | ||
| // Unless one sequence consists of common items only, | ||
| // therefore the other trimmed index interval consists of changes only, | ||
| // find common items in the trimmed index intervals. | ||
| const nCommonFR = nCommonF + nCommonR; | ||
| if (aLength !== nCommonFR && bLength !== nCommonFR) { | ||
| const nChange = 0; // number of change items is not yet known | ||
| const transposed = false; // call the original unwrapped functions | ||
| const callbacks = [ | ||
| { | ||
| foundSubsequence, | ||
| isCommon | ||
| } | ||
| ]; | ||
| // Indexes in sequence a of last points in furthest reaching paths | ||
| // from outside the start at top left in the forward direction: | ||
| const aIndexesF = [NOT_YET_SET]; | ||
| // from the end at bottom right in the reverse direction: | ||
| const aIndexesR = [NOT_YET_SET]; | ||
| // Initialize one object as output of all calls to divide function. | ||
| const division = { | ||
| aCommonFollowing: NOT_YET_SET, | ||
| aCommonPreceding: NOT_YET_SET, | ||
| aEndPreceding: NOT_YET_SET, | ||
| aStartFollowing: NOT_YET_SET, | ||
| bCommonFollowing: NOT_YET_SET, | ||
| bCommonPreceding: NOT_YET_SET, | ||
| bEndPreceding: NOT_YET_SET, | ||
| bStartFollowing: NOT_YET_SET, | ||
| nChangeFollowing: NOT_YET_SET, | ||
| nChangePreceding: NOT_YET_SET, | ||
| nCommonFollowing: NOT_YET_SET, | ||
| nCommonPreceding: NOT_YET_SET | ||
| }; | ||
| // Find and return common subsequences in the trimmed index intervals. | ||
| findSubsequences( | ||
| nChange, | ||
| aStart, | ||
| aEnd, | ||
| bStart, | ||
| bEnd, | ||
| transposed, | ||
| callbacks, | ||
| aIndexesF, | ||
| aIndexesR, | ||
| division | ||
| ); | ||
| } | ||
| if (nCommonR !== 0) { | ||
| foundSubsequence(nCommonR, aEnd, bEnd); | ||
| } | ||
| } | ||
| } | ||
| return build; | ||
| } | ||
| var buildExports = requireBuild(); | ||
| var diffSequences = /*@__PURE__*/getDefaultExportFromCjs(buildExports); | ||
| const IS_RECORD_SYMBOL = "@@__IMMUTABLE_RECORD__@@"; | ||
| const IS_COLLECTION_SYMBOL = "@@__IMMUTABLE_ITERABLE__@@"; | ||
| function isImmutable(v) { | ||
| return v && (v[IS_COLLECTION_SYMBOL] || v[IS_RECORD_SYMBOL]); | ||
| } | ||
| const OBJECT_PROTO = Object.getPrototypeOf({}); | ||
| function getUnserializableMessage(err) { | ||
| if (err instanceof Error) return `<unserializable>: ${err.message}`; | ||
| if (typeof err === "string") return `<unserializable>: ${err}`; | ||
| return "<unserializable>"; | ||
| } | ||
| // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm | ||
| function serializeValue(val, seen = /* @__PURE__ */ new WeakMap()) { | ||
| if (!val || typeof val === "string") return val; | ||
| if (val instanceof Error && "toJSON" in val && typeof val.toJSON === "function") { | ||
| const jsonValue = val.toJSON(); | ||
| if (jsonValue && jsonValue !== val && typeof jsonValue === "object") { | ||
| if (typeof val.message === "string") safe(() => jsonValue.message ??= normalizeErrorMessage(val.message)); | ||
| if (typeof val.stack === "string") safe(() => jsonValue.stack ??= val.stack); | ||
| if (typeof val.name === "string") safe(() => jsonValue.name ??= val.name); | ||
| if (val.cause != null) safe(() => jsonValue.cause ??= serializeValue(val.cause, seen)); | ||
| } | ||
| return serializeValue(jsonValue, seen); | ||
| } | ||
| if (typeof val === "function") return `Function<${val.name || "anonymous"}>`; | ||
| if (typeof val === "symbol") return val.toString(); | ||
| if (typeof val !== "object") return val; | ||
| if (typeof Buffer !== "undefined" && val instanceof Buffer) return `<Buffer(${val.length}) ...>`; | ||
| if (typeof Uint8Array !== "undefined" && val instanceof Uint8Array) return `<Uint8Array(${val.length}) ...>`; | ||
| // cannot serialize immutables as immutables | ||
| if (isImmutable(val)) return serializeValue(val.toJSON(), seen); | ||
| if (val instanceof Promise || val.constructor && val.constructor.prototype === "AsyncFunction") return "Promise"; | ||
| if (typeof Element !== "undefined" && val instanceof Element) return val.tagName; | ||
| if (typeof val.toJSON === "function") return serializeValue(val.toJSON(), seen); | ||
| if (seen.has(val)) return seen.get(val); | ||
| if (Array.isArray(val)) { | ||
| // eslint-disable-next-line unicorn/no-new-array -- we need to keep sparse arrays ([1,,3]) | ||
| const clone = new Array(val.length); | ||
| seen.set(val, clone); | ||
| val.forEach((e, i) => { | ||
| try { | ||
| clone[i] = serializeValue(e, seen); | ||
| } catch (err) { | ||
| clone[i] = getUnserializableMessage(err); | ||
| } | ||
| }); | ||
| return clone; | ||
| } else { | ||
| // Objects with `Error` constructors appear to cause problems during worker communication | ||
| // using `MessagePort`, so the serialized error object is being recreated as plain object. | ||
| const clone = Object.create(null); | ||
| seen.set(val, clone); | ||
| let obj = val; | ||
| while (obj && obj !== OBJECT_PROTO) { | ||
| Object.getOwnPropertyNames(obj).forEach((key) => { | ||
| if (key in clone) return; | ||
| try { | ||
| clone[key] = serializeValue(val[key], seen); | ||
| } catch (err) { | ||
| // delete in case it has a setter from prototype that might throw | ||
| delete clone[key]; | ||
| clone[key] = getUnserializableMessage(err); | ||
| } | ||
| }); | ||
| obj = Object.getPrototypeOf(obj); | ||
| } | ||
| if (val instanceof Error) safe(() => clone.message = normalizeErrorMessage(val.message)); | ||
| return clone; | ||
| } | ||
| } | ||
| function safe(fn) { | ||
| try { | ||
| return fn(); | ||
| } catch {} | ||
| } | ||
| function normalizeErrorMessage(message) { | ||
| return message.replace(/\(0\s?,\s?__vite_ssr_import_\d+__.(\w+)\)/g, "$1").replace(/__(vite_ssr_import|vi_import)_\d+__\./g, "").replace(/getByTestId('__vitest_\d+__')/g, "page"); | ||
| } | ||
| const SAFE_TIMERS_SYMBOL = Symbol("vitest:SAFE_TIMERS"); | ||
| function getSafeTimers() { | ||
| const { setTimeout: safeSetTimeout, setInterval: safeSetInterval, clearInterval: safeClearInterval, clearTimeout: safeClearTimeout, setImmediate: safeSetImmediate, clearImmediate: safeClearImmediate, queueMicrotask: safeQueueMicrotask } = globalThis[SAFE_TIMERS_SYMBOL] || globalThis; | ||
| const { nextTick: safeNextTick } = globalThis[SAFE_TIMERS_SYMBOL] || globalThis.process || {}; | ||
| return { | ||
| nextTick: safeNextTick, | ||
| setTimeout: safeSetTimeout, | ||
| setInterval: safeSetInterval, | ||
| clearInterval: safeClearInterval, | ||
| clearTimeout: safeClearTimeout, | ||
| setImmediate: safeSetImmediate, | ||
| clearImmediate: safeClearImmediate, | ||
| queueMicrotask: safeQueueMicrotask | ||
| }; | ||
| } | ||
| function setSafeTimers() { | ||
| const { setTimeout: safeSetTimeout, setInterval: safeSetInterval, clearInterval: safeClearInterval, clearTimeout: safeClearTimeout, setImmediate: safeSetImmediate, clearImmediate: safeClearImmediate, queueMicrotask: safeQueueMicrotask } = globalThis; | ||
| const { nextTick: safeNextTick } = globalThis.process || {}; | ||
| const timers = { | ||
| nextTick: safeNextTick, | ||
| setTimeout: safeSetTimeout, | ||
| setInterval: safeSetInterval, | ||
| clearInterval: safeClearInterval, | ||
| clearTimeout: safeClearTimeout, | ||
| setImmediate: safeSetImmediate, | ||
| clearImmediate: safeClearImmediate, | ||
| queueMicrotask: safeQueueMicrotask | ||
| }; | ||
| globalThis[SAFE_TIMERS_SYMBOL] = timers; | ||
| } | ||
| /** | ||
| * Returns a promise that resolves after the specified duration. | ||
| * | ||
| * @param timeout - Delay in milliseconds | ||
| * @param scheduler - Timer function to use, defaults to `setTimeout`. Useful for mocked timers. | ||
| * | ||
| * @example | ||
| * await delay(100) | ||
| * | ||
| * @example | ||
| * // With mocked timers | ||
| * const { setTimeout } = getSafeTimers() | ||
| * await delay(100, setTimeout) | ||
| */ | ||
| function delay(timeout, scheduler = setTimeout) { | ||
| return new Promise((resolve) => scheduler(resolve, timeout)); | ||
| } | ||
| // src/vlq.ts | ||
| var comma = ",".charCodeAt(0); | ||
| 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; | ||
| } | ||
| function decodeInteger(reader, relative) { | ||
| let value = 0; | ||
| let shift = 0; | ||
| let integer = 0; | ||
| do { | ||
| const c = reader.next(); | ||
| integer = charToInt[c]; | ||
| value |= (integer & 31) << shift; | ||
| shift += 5; | ||
| } while (integer & 32); | ||
| const shouldNegate = value & 1; | ||
| value >>>= 1; | ||
| if (shouldNegate) { | ||
| value = -2147483648 | -value; | ||
| } | ||
| return relative + value; | ||
| } | ||
| function hasMoreVlq(reader, max) { | ||
| if (reader.pos >= max) return false; | ||
| return reader.peek() !== comma; | ||
| } | ||
| var StringReader = class { | ||
| constructor(buffer) { | ||
| this.pos = 0; | ||
| this.buffer = buffer; | ||
| } | ||
| next() { | ||
| return this.buffer.charCodeAt(this.pos++); | ||
| } | ||
| peek() { | ||
| return this.buffer.charCodeAt(this.pos); | ||
| } | ||
| indexOf(char) { | ||
| const { buffer, pos } = this; | ||
| const idx = buffer.indexOf(char, pos); | ||
| return idx === -1 ? buffer.length : idx; | ||
| } | ||
| }; | ||
| // src/sourcemap-codec.ts | ||
| function decode(mappings) { | ||
| const { length } = mappings; | ||
| const reader = new StringReader(mappings); | ||
| const decoded = []; | ||
| let genColumn = 0; | ||
| let sourcesIndex = 0; | ||
| let sourceLine = 0; | ||
| let sourceColumn = 0; | ||
| let namesIndex = 0; | ||
| do { | ||
| const semi = reader.indexOf(";"); | ||
| const line = []; | ||
| let sorted = true; | ||
| let lastCol = 0; | ||
| genColumn = 0; | ||
| while (reader.pos < semi) { | ||
| let seg; | ||
| genColumn = decodeInteger(reader, genColumn); | ||
| if (genColumn < lastCol) sorted = false; | ||
| lastCol = genColumn; | ||
| if (hasMoreVlq(reader, semi)) { | ||
| sourcesIndex = decodeInteger(reader, sourcesIndex); | ||
| sourceLine = decodeInteger(reader, sourceLine); | ||
| sourceColumn = decodeInteger(reader, sourceColumn); | ||
| if (hasMoreVlq(reader, semi)) { | ||
| namesIndex = decodeInteger(reader, namesIndex); | ||
| seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex]; | ||
| } else { | ||
| seg = [genColumn, sourcesIndex, sourceLine, sourceColumn]; | ||
| } | ||
| } else { | ||
| seg = [genColumn]; | ||
| } | ||
| line.push(seg); | ||
| reader.pos++; | ||
| } | ||
| if (!sorted) sort(line); | ||
| decoded.push(line); | ||
| reader.pos = semi + 1; | ||
| } while (reader.pos <= length); | ||
| return decoded; | ||
| } | ||
| function sort(line) { | ||
| line.sort(sortComparator$1); | ||
| } | ||
| function sortComparator$1(a, b) { | ||
| return a[0] - b[0]; | ||
| } | ||
| // Matches the scheme of a URL, eg "http://" | ||
| const schemeRegex = /^[\w+.-]+:\/\//; | ||
| /** | ||
| * Matches the parts of a URL: | ||
| * 1. Scheme, including ":", guaranteed. | ||
| * 2. User/password, including "@", optional. | ||
| * 3. Host, guaranteed. | ||
| * 4. Port, including ":", optional. | ||
| * 5. Path, including "/", optional. | ||
| * 6. Query, including "?", optional. | ||
| * 7. Hash, including "#", optional. | ||
| */ | ||
| const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/; | ||
| /** | ||
| * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start | ||
| * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive). | ||
| * | ||
| * 1. Host, optional. | ||
| * 2. Path, which may include "/", guaranteed. | ||
| * 3. Query, including "?", optional. | ||
| * 4. Hash, including "#", optional. | ||
| */ | ||
| const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i; | ||
| function isAbsoluteUrl(input) { | ||
| return schemeRegex.test(input); | ||
| } | ||
| function isSchemeRelativeUrl(input) { | ||
| return input.startsWith('//'); | ||
| } | ||
| function isAbsolutePath(input) { | ||
| return input.startsWith('/'); | ||
| } | ||
| function isFileUrl(input) { | ||
| return input.startsWith('file:'); | ||
| } | ||
| function isRelative(input) { | ||
| return /^[.?#]/.test(input); | ||
| } | ||
| function parseAbsoluteUrl(input) { | ||
| const match = urlRegex.exec(input); | ||
| return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || ''); | ||
| } | ||
| function parseFileUrl(input) { | ||
| const match = fileRegex.exec(input); | ||
| const path = match[2]; | ||
| return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || ''); | ||
| } | ||
| function makeUrl(scheme, user, host, port, path, query, hash) { | ||
| return { | ||
| scheme, | ||
| user, | ||
| host, | ||
| port, | ||
| path, | ||
| query, | ||
| hash, | ||
| type: 7 /* Absolute */, | ||
| }; | ||
| } | ||
| function parseUrl(input) { | ||
| if (isSchemeRelativeUrl(input)) { | ||
| const url = parseAbsoluteUrl('http:' + input); | ||
| url.scheme = ''; | ||
| url.type = 6 /* SchemeRelative */; | ||
| return url; | ||
| } | ||
| if (isAbsolutePath(input)) { | ||
| const url = parseAbsoluteUrl('http://foo.com' + input); | ||
| url.scheme = ''; | ||
| url.host = ''; | ||
| url.type = 5 /* AbsolutePath */; | ||
| return url; | ||
| } | ||
| if (isFileUrl(input)) | ||
| return parseFileUrl(input); | ||
| if (isAbsoluteUrl(input)) | ||
| return parseAbsoluteUrl(input); | ||
| const url = parseAbsoluteUrl('http://foo.com/' + input); | ||
| url.scheme = ''; | ||
| url.host = ''; | ||
| url.type = input | ||
| ? input.startsWith('?') | ||
| ? 3 /* Query */ | ||
| : input.startsWith('#') | ||
| ? 2 /* Hash */ | ||
| : 4 /* RelativePath */ | ||
| : 1 /* Empty */; | ||
| return url; | ||
| } | ||
| function stripPathFilename(path) { | ||
| // If a path ends with a parent directory "..", then it's a relative path with excess parent | ||
| // paths. It's not a file, so we can't strip it. | ||
| if (path.endsWith('/..')) | ||
| return path; | ||
| const index = path.lastIndexOf('/'); | ||
| return path.slice(0, index + 1); | ||
| } | ||
| function mergePaths(url, base) { | ||
| normalizePath(base, base.type); | ||
| // If the path is just a "/", then it was an empty path to begin with (remember, we're a relative | ||
| // path). | ||
| if (url.path === '/') { | ||
| url.path = base.path; | ||
| } | ||
| else { | ||
| // Resolution happens relative to the base path's directory, not the file. | ||
| url.path = stripPathFilename(base.path) + url.path; | ||
| } | ||
| } | ||
| /** | ||
| * The path can have empty directories "//", unneeded parents "foo/..", or current directory | ||
| * "foo/.". We need to normalize to a standard representation. | ||
| */ | ||
| function normalizePath(url, type) { | ||
| const rel = type <= 4 /* RelativePath */; | ||
| const pieces = url.path.split('/'); | ||
| // We need to preserve the first piece always, so that we output a leading slash. The item at | ||
| // pieces[0] is an empty string. | ||
| let pointer = 1; | ||
| // Positive is the number of real directories we've output, used for popping a parent directory. | ||
| // Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo". | ||
| let positive = 0; | ||
| // We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will | ||
| // generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a | ||
| // real directory, we won't need to append, unless the other conditions happen again. | ||
| let addTrailingSlash = false; | ||
| for (let i = 1; i < pieces.length; i++) { | ||
| const piece = pieces[i]; | ||
| // An empty directory, could be a trailing slash, or just a double "//" in the path. | ||
| if (!piece) { | ||
| addTrailingSlash = true; | ||
| continue; | ||
| } | ||
| // If we encounter a real directory, then we don't need to append anymore. | ||
| addTrailingSlash = false; | ||
| // A current directory, which we can always drop. | ||
| if (piece === '.') | ||
| continue; | ||
| // A parent directory, we need to see if there are any real directories we can pop. Else, we | ||
| // have an excess of parents, and we'll need to keep the "..". | ||
| if (piece === '..') { | ||
| if (positive) { | ||
| addTrailingSlash = true; | ||
| positive--; | ||
| pointer--; | ||
| } | ||
| else if (rel) { | ||
| // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute | ||
| // URL, protocol relative URL, or an absolute path, we don't need to keep excess. | ||
| pieces[pointer++] = piece; | ||
| } | ||
| continue; | ||
| } | ||
| // We've encountered a real directory. Move it to the next insertion pointer, which accounts for | ||
| // any popped or dropped directories. | ||
| pieces[pointer++] = piece; | ||
| positive++; | ||
| } | ||
| let path = ''; | ||
| for (let i = 1; i < pointer; i++) { | ||
| path += '/' + pieces[i]; | ||
| } | ||
| if (!path || (addTrailingSlash && !path.endsWith('/..'))) { | ||
| path += '/'; | ||
| } | ||
| url.path = path; | ||
| } | ||
| /** | ||
| * Attempts to resolve `input` URL/path relative to `base`. | ||
| */ | ||
| function resolve(input, base) { | ||
| if (!input && !base) | ||
| return ''; | ||
| const url = parseUrl(input); | ||
| let inputType = url.type; | ||
| if (base && inputType !== 7 /* Absolute */) { | ||
| const baseUrl = parseUrl(base); | ||
| const baseType = baseUrl.type; | ||
| switch (inputType) { | ||
| case 1 /* Empty */: | ||
| url.hash = baseUrl.hash; | ||
| // fall through | ||
| case 2 /* Hash */: | ||
| url.query = baseUrl.query; | ||
| // fall through | ||
| case 3 /* Query */: | ||
| case 4 /* RelativePath */: | ||
| mergePaths(url, baseUrl); | ||
| // fall through | ||
| case 5 /* AbsolutePath */: | ||
| // The host, user, and port are joined, you can't copy one without the others. | ||
| url.user = baseUrl.user; | ||
| url.host = baseUrl.host; | ||
| url.port = baseUrl.port; | ||
| // fall through | ||
| case 6 /* SchemeRelative */: | ||
| // The input doesn't have a schema at least, so we need to copy at least that over. | ||
| url.scheme = baseUrl.scheme; | ||
| } | ||
| if (baseType > inputType) | ||
| inputType = baseType; | ||
| } | ||
| normalizePath(url, inputType); | ||
| const queryHash = url.query + url.hash; | ||
| switch (inputType) { | ||
| // This is impossible, because of the empty checks at the start of the function. | ||
| // case UrlType.Empty: | ||
| case 2 /* Hash */: | ||
| case 3 /* Query */: | ||
| return queryHash; | ||
| case 4 /* RelativePath */: { | ||
| // The first char is always a "/", and we need it to be relative. | ||
| const path = url.path.slice(1); | ||
| if (!path) | ||
| return queryHash || '.'; | ||
| if (isRelative(base || input) && !isRelative(path)) { | ||
| // If base started with a leading ".", or there is no base and input started with a ".", | ||
| // then we need to ensure that the relative path starts with a ".". We don't know if | ||
| // relative starts with a "..", though, so check before prepending. | ||
| return './' + path + queryHash; | ||
| } | ||
| return path + queryHash; | ||
| } | ||
| case 5 /* AbsolutePath */: | ||
| return url.path + queryHash; | ||
| default: | ||
| return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash; | ||
| } | ||
| } | ||
| // src/trace-mapping.ts | ||
| // src/strip-filename.ts | ||
| function stripFilename(path) { | ||
| if (!path) return ""; | ||
| const index = path.lastIndexOf("/"); | ||
| return path.slice(0, index + 1); | ||
| } | ||
| // src/resolve.ts | ||
| function resolver(mapUrl, sourceRoot) { | ||
| const from = stripFilename(mapUrl); | ||
| const prefix = sourceRoot ? sourceRoot + "/" : ""; | ||
| return (source) => resolve(prefix + (source || ""), from); | ||
| } | ||
| // src/sourcemap-segment.ts | ||
| var COLUMN = 0; | ||
| var SOURCES_INDEX = 1; | ||
| var SOURCE_LINE = 2; | ||
| var SOURCE_COLUMN = 3; | ||
| var NAMES_INDEX = 4; | ||
| var REV_GENERATED_LINE = 1; | ||
| var REV_GENERATED_COLUMN = 2; | ||
| // src/sort.ts | ||
| function maybeSort(mappings, owned) { | ||
| const unsortedIndex = nextUnsortedSegmentLine(mappings, 0); | ||
| if (unsortedIndex === mappings.length) return mappings; | ||
| if (!owned) mappings = mappings.slice(); | ||
| for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) { | ||
| mappings[i] = sortSegments(mappings[i], owned); | ||
| } | ||
| return mappings; | ||
| } | ||
| function nextUnsortedSegmentLine(mappings, start) { | ||
| for (let i = start; i < mappings.length; i++) { | ||
| if (!isSorted(mappings[i])) return i; | ||
| } | ||
| return mappings.length; | ||
| } | ||
| function isSorted(line) { | ||
| for (let j = 1; j < line.length; j++) { | ||
| if (line[j][COLUMN] < line[j - 1][COLUMN]) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| function sortSegments(line, owned) { | ||
| if (!owned) line = line.slice(); | ||
| return line.sort(sortComparator); | ||
| } | ||
| function sortComparator(a, b) { | ||
| return a[COLUMN] - b[COLUMN]; | ||
| } | ||
| // src/by-source.ts | ||
| function buildBySources(decoded, memos) { | ||
| const sources = memos.map(() => []); | ||
| for (let i = 0; i < decoded.length; i++) { | ||
| const line = decoded[i]; | ||
| for (let j = 0; j < line.length; j++) { | ||
| const seg = line[j]; | ||
| if (seg.length === 1) continue; | ||
| const sourceIndex2 = seg[SOURCES_INDEX]; | ||
| const sourceLine = seg[SOURCE_LINE]; | ||
| const sourceColumn = seg[SOURCE_COLUMN]; | ||
| const source = sources[sourceIndex2]; | ||
| const segs = source[sourceLine] || (source[sourceLine] = []); | ||
| segs.push([sourceColumn, i, seg[COLUMN]]); | ||
| } | ||
| } | ||
| for (let i = 0; i < sources.length; i++) { | ||
| const source = sources[i]; | ||
| for (let j = 0; j < source.length; j++) { | ||
| const line = source[j]; | ||
| if (line) line.sort(sortComparator); | ||
| } | ||
| } | ||
| return sources; | ||
| } | ||
| // src/binary-search.ts | ||
| var found = false; | ||
| function binarySearch(haystack, needle, low, high) { | ||
| while (low <= high) { | ||
| const mid = low + (high - low >> 1); | ||
| const cmp = haystack[mid][COLUMN] - needle; | ||
| if (cmp === 0) { | ||
| found = true; | ||
| return mid; | ||
| } | ||
| if (cmp < 0) { | ||
| low = mid + 1; | ||
| } else { | ||
| high = mid - 1; | ||
| } | ||
| } | ||
| found = false; | ||
| return low - 1; | ||
| } | ||
| function upperBound(haystack, needle, index) { | ||
| for (let i = index + 1; i < haystack.length; index = i++) { | ||
| if (haystack[i][COLUMN] !== needle) break; | ||
| } | ||
| return index; | ||
| } | ||
| function lowerBound(haystack, needle, index) { | ||
| for (let i = index - 1; i >= 0; index = i--) { | ||
| if (haystack[i][COLUMN] !== needle) break; | ||
| } | ||
| return index; | ||
| } | ||
| function memoizedState$1() { | ||
| return { | ||
| lastKey: -1, | ||
| lastNeedle: -1, | ||
| lastIndex: -1 | ||
| }; | ||
| } | ||
| function memoizedBinarySearch(haystack, needle, state, key) { | ||
| const { lastKey, lastNeedle, lastIndex } = state; | ||
| let low = 0; | ||
| let high = haystack.length - 1; | ||
| if (key === lastKey) { | ||
| if (needle === lastNeedle) { | ||
| found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle; | ||
| return lastIndex; | ||
| } | ||
| if (needle >= lastNeedle) { | ||
| low = lastIndex === -1 ? 0 : lastIndex; | ||
| } else { | ||
| high = lastIndex; | ||
| } | ||
| } | ||
| state.lastKey = key; | ||
| state.lastNeedle = needle; | ||
| return state.lastIndex = binarySearch(haystack, needle, low, high); | ||
| } | ||
| // src/types.ts | ||
| function parse(map) { | ||
| return typeof map === "string" ? JSON.parse(map) : map; | ||
| } | ||
| // src/trace-mapping.ts | ||
| var LINE_GTR_ZERO = "`line` must be greater than 0 (lines start at line 1)"; | ||
| var COL_GTR_EQ_ZERO = "`column` must be greater than or equal to 0 (columns start at column 0)"; | ||
| var LEAST_UPPER_BOUND = -1; | ||
| var GREATEST_LOWER_BOUND = 1; | ||
| var TraceMap = class { | ||
| constructor(map, mapUrl) { | ||
| const isString = typeof map === "string"; | ||
| if (!isString && map._decodedMemo) return map; | ||
| const parsed = parse(map); | ||
| const { version, file, names, sourceRoot, sources, sourcesContent } = parsed; | ||
| this.version = version; | ||
| this.file = file; | ||
| this.names = names || []; | ||
| this.sourceRoot = sourceRoot; | ||
| this.sources = sources; | ||
| this.sourcesContent = sourcesContent; | ||
| this.ignoreList = parsed.ignoreList || parsed.x_google_ignoreList || void 0; | ||
| const resolve = resolver(mapUrl, sourceRoot); | ||
| this.resolvedSources = sources.map(resolve); | ||
| const { mappings } = parsed; | ||
| if (typeof mappings === "string") { | ||
| this._encoded = mappings; | ||
| this._decoded = void 0; | ||
| } else if (Array.isArray(mappings)) { | ||
| this._encoded = void 0; | ||
| this._decoded = maybeSort(mappings, isString); | ||
| } else if (parsed.sections) { | ||
| throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`); | ||
| } else { | ||
| throw new Error(`invalid source map: ${JSON.stringify(parsed)}`); | ||
| } | ||
| this._decodedMemo = memoizedState$1(); | ||
| this._bySources = void 0; | ||
| this._bySourceMemos = void 0; | ||
| } | ||
| }; | ||
| function cast(map) { | ||
| return map; | ||
| } | ||
| function decodedMappings(map) { | ||
| var _a; | ||
| return (_a = cast(map))._decoded || (_a._decoded = decode(cast(map)._encoded)); | ||
| } | ||
| function originalPositionFor(map, needle) { | ||
| let { line, column, bias } = needle; | ||
| line--; | ||
| if (line < 0) throw new Error(LINE_GTR_ZERO); | ||
| if (column < 0) throw new Error(COL_GTR_EQ_ZERO); | ||
| const decoded = decodedMappings(map); | ||
| if (line >= decoded.length) return OMapping(null, null, null, null); | ||
| const segments = decoded[line]; | ||
| const index = traceSegmentInternal( | ||
| segments, | ||
| cast(map)._decodedMemo, | ||
| line, | ||
| column, | ||
| bias || GREATEST_LOWER_BOUND | ||
| ); | ||
| if (index === -1) return OMapping(null, null, null, null); | ||
| const segment = segments[index]; | ||
| if (segment.length === 1) return OMapping(null, null, null, null); | ||
| const { names, resolvedSources } = map; | ||
| return OMapping( | ||
| resolvedSources[segment[SOURCES_INDEX]], | ||
| segment[SOURCE_LINE] + 1, | ||
| segment[SOURCE_COLUMN], | ||
| segment.length === 5 ? names[segment[NAMES_INDEX]] : null | ||
| ); | ||
| } | ||
| function generatedPositionFor(map, needle) { | ||
| const { source, line, column, bias } = needle; | ||
| return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false); | ||
| } | ||
| function eachMapping(map, cb) { | ||
| const decoded = decodedMappings(map); | ||
| const { names, resolvedSources } = map; | ||
| for (let i = 0; i < decoded.length; i++) { | ||
| const line = decoded[i]; | ||
| for (let j = 0; j < line.length; j++) { | ||
| const seg = line[j]; | ||
| const generatedLine = i + 1; | ||
| const generatedColumn = seg[0]; | ||
| let source = null; | ||
| let originalLine = null; | ||
| let originalColumn = null; | ||
| let name = null; | ||
| if (seg.length !== 1) { | ||
| source = resolvedSources[seg[1]]; | ||
| originalLine = seg[2] + 1; | ||
| originalColumn = seg[3]; | ||
| } | ||
| if (seg.length === 5) name = names[seg[4]]; | ||
| cb({ | ||
| generatedLine, | ||
| generatedColumn, | ||
| source, | ||
| originalLine, | ||
| originalColumn, | ||
| name | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| function OMapping(source, line, column, name) { | ||
| return { source, line, column, name }; | ||
| } | ||
| function GMapping(line, column) { | ||
| return { line, column }; | ||
| } | ||
| function traceSegmentInternal(segments, memo, line, column, bias) { | ||
| let index = memoizedBinarySearch(segments, column, memo, line); | ||
| if (found) { | ||
| index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index); | ||
| } else if (bias === LEAST_UPPER_BOUND) index++; | ||
| if (index === -1 || index === segments.length) return -1; | ||
| return index; | ||
| } | ||
| function generatedPosition(map, source, line, column, bias, all) { | ||
| var _a, _b; | ||
| line--; | ||
| if (line < 0) throw new Error(LINE_GTR_ZERO); | ||
| if (column < 0) throw new Error(COL_GTR_EQ_ZERO); | ||
| const { sources, resolvedSources } = map; | ||
| let sourceIndex2 = sources.indexOf(source); | ||
| if (sourceIndex2 === -1) sourceIndex2 = resolvedSources.indexOf(source); | ||
| if (sourceIndex2 === -1) return all ? [] : GMapping(null, null); | ||
| const bySourceMemos = (_a = cast(map))._bySourceMemos || (_a._bySourceMemos = sources.map(memoizedState$1)); | ||
| const generated = (_b = cast(map))._bySources || (_b._bySources = buildBySources(decodedMappings(map), bySourceMemos)); | ||
| const segments = generated[sourceIndex2][line]; | ||
| if (segments == null) return all ? [] : GMapping(null, null); | ||
| const memo = bySourceMemos[sourceIndex2]; | ||
| const index = traceSegmentInternal(segments, memo, line, column, bias); | ||
| if (index === -1) return GMapping(null, null); | ||
| const segment = segments[index]; | ||
| return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]); | ||
| } | ||
| const CHROME_IE_STACK_REGEXP = /^\s*at .*(?:\S:\d+|\(native\))/m; | ||
| const SAFARI_NATIVE_CODE_REGEXP = /^(?:eval@)?(?:\[native code\])?$/; | ||
| const stackIgnorePatterns = [ | ||
| "node:internal", | ||
| /\/packages\/\w+\/dist\//, | ||
| /\/@vitest\/\w+\/dist\//, | ||
| "/vitest/dist/", | ||
| "/vitest/src/", | ||
| "/packages/expect/src/", | ||
| "/packages/snapshot/src/", | ||
| "/node_modules/chai/", | ||
| "/node_modules/tinyspy/", | ||
| "/vite/dist/node/module-runner", | ||
| "/rolldown-vite/dist/node/module-runner", | ||
| "/deps/chunk-", | ||
| "/deps/@vitest", | ||
| "/deps/loupe", | ||
| "/deps/chai", | ||
| "/browser-playwright/dist/locators.js", | ||
| "/browser-webdriverio/dist/locators.js", | ||
| "/browser-preview/dist/locators.js", | ||
| /node:\w+/, | ||
| /__vitest_test__/, | ||
| /__vitest_browser__/, | ||
| "/@id/__x00__vitest/browser", | ||
| /\/deps\/vitest_/, | ||
| "/deps/vitest.js" | ||
| ]; | ||
| const NOW_LENGTH = Date.now().toString().length; | ||
| const REGEXP_VITEST = new RegExp(`vitest=\\d{${NOW_LENGTH}}`); | ||
| function extractLocation(urlLike) { | ||
| // Fail-fast but return locations like "(native)" | ||
| if (!urlLike.includes(":")) return [urlLike]; | ||
| const parts = /(.+?)(?::(\d+))?(?::(\d+))?$/.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); | ||
| } | ||
| if (url.includes("vitest=")) url = url.replace(REGEXP_VITEST, "").replace(/[?&]$/, ""); | ||
| 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"); | ||
| // 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) : void 0; | ||
| 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) ? 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); | ||
| // normalize Windows path (\ -> /) | ||
| file = file.startsWith("node:") || file.startsWith("internal:") ? file : resolve$1(file); | ||
| if (method) method = method.replace(/\(0\s?,\s?__vite_ssr_import_\d+__.(\w+)\)/g, "$1").replace(/__(vite_ssr_import|vi_import)_\d+__\./g, "").replace(/(Object\.)?__vite_ssr_export_default__\s?/g, ""); | ||
| return { | ||
| method, | ||
| file, | ||
| line: Number.parseInt(lineNumber), | ||
| column: Number.parseInt(columnNumber) | ||
| }; | ||
| } | ||
| function createStackString(stacks) { | ||
| return stacks.map((stack) => { | ||
| const line = `${stack.file}:${stack.line}:${stack.column}`; | ||
| if (stack.method) return ` at ${stack.method}(${line})`; | ||
| return ` at ${line}`; | ||
| }).join("\n"); | ||
| } | ||
| function parseStacktrace(stack, options = {}) { | ||
| const { ignoreStackEntries = stackIgnorePatterns } = options; | ||
| let stacks = !CHROME_IE_STACK_REGEXP.test(stack) ? parseFFOrSafariStackTrace(stack) : parseV8Stacktrace(stack); | ||
| // remove vi.defineHelper's internal stacks | ||
| const helperIndex = stacks.findLastIndex((s) => s.method.includes("__VITEST_HELPER__")); | ||
| if (helperIndex >= 0) stacks = stacks.slice(helperIndex + 1); | ||
| return stacks.map((stack) => { | ||
| if (options.getUrlId) stack.file = options.getUrlId(stack.file); | ||
| const map = options.getSourceMap?.(stack.file); | ||
| if (!map || typeof map !== "object" || !map.version) return shouldFilter(ignoreStackEntries, stack.file) ? null : stack; | ||
| const traceMap = new DecodedMap(map, stack.file); | ||
| if (stack.line <= 0 || stack.column <= 0) return stack; | ||
| const position = getOriginalPosition(traceMap, { | ||
| line: stack.line, | ||
| column: stack.column - 1 | ||
| }); | ||
| if (!position) return stack; | ||
| const { line, column, source, name } = position; | ||
| let file = source || stack.file; | ||
| if (/\/\w:\//.test(file)) file = file.slice(1); | ||
| if (shouldFilter(ignoreStackEntries, file)) return null; | ||
| if (line != null && column != null) return { | ||
| line, | ||
| column: column + 1, | ||
| file, | ||
| method: name || stack.method | ||
| }; | ||
| return stack; | ||
| }).filter((s) => s != null); | ||
| } | ||
| function shouldFilter(ignoreStackEntries, file) { | ||
| return ignoreStackEntries.some((p) => file.match(p)); | ||
| } | ||
| function parseFFOrSafariStackTrace(stack) { | ||
| return stack.split("\n").map((line) => parseSingleFFOrSafariStack(line)).filter(notNullish); | ||
| } | ||
| function parseV8Stacktrace(stack) { | ||
| return stack.split("\n").map((line) => parseSingleV8Stack(line)).filter(notNullish); | ||
| } | ||
| function parseErrorStacktrace(e, options = {}) { | ||
| if (!e || isPrimitive(e)) return []; | ||
| if ("stacks" in e && e.stacks) return e.stacks; | ||
| const stackStr = e.stack || ""; | ||
| // if "stack" property was overwritten at runtime to be something else, | ||
| // ignore the value because we don't know how to process it | ||
| let stackFrames = typeof stackStr === "string" ? parseStacktrace(stackStr, options) : []; | ||
| if (!stackFrames.length) { | ||
| const e_ = e; | ||
| if (e_.fileName != null && e_.lineNumber != null && e_.columnNumber != null) stackFrames = parseStacktrace(`${e_.fileName}:${e_.lineNumber}:${e_.columnNumber}`, options); | ||
| if (e_.sourceURL != null && e_.line != null && e_._column != null) stackFrames = parseStacktrace(`${e_.sourceURL}:${e_.line}:${e_.column}`, options); | ||
| } | ||
| if (options.frameFilter) stackFrames = stackFrames.filter((f) => options.frameFilter(e, f) !== false); | ||
| e.stacks = stackFrames; | ||
| return stackFrames; | ||
| } | ||
| class DecodedMap { | ||
| _encoded; | ||
| _decoded; | ||
| _decodedMemo; | ||
| url; | ||
| version; | ||
| names = []; | ||
| resolvedSources; | ||
| constructor(map, from) { | ||
| this.map = map; | ||
| const { mappings, names, sources } = map; | ||
| this.version = map.version; | ||
| this.names = names || []; | ||
| this._encoded = mappings || ""; | ||
| this._decodedMemo = memoizedState(); | ||
| this.url = from; | ||
| this.resolvedSources = (sources || []).map((s) => resolve$1(from, "..", s || "")); | ||
| } | ||
| } | ||
| function memoizedState() { | ||
| return { | ||
| lastKey: -1, | ||
| lastNeedle: -1, | ||
| lastIndex: -1 | ||
| }; | ||
| } | ||
| function getOriginalPosition(map, needle) { | ||
| const result = originalPositionFor(map, needle); | ||
| if (result.column == null) return null; | ||
| return result; | ||
| } | ||
| export { DecodedMap as D, TraceMap as T, getSafeTimers as a, serializeValue as b, createStackString as c, getDefaultExportFromCjs as d, diffSequences as e, parseSingleStack as f, getOriginalPosition as g, commonjsGlobal as h, delay as i, parseErrorStacktrace as j, generatedPositionFor as k, eachMapping as l, stackIgnorePatterns as m, originalPositionFor as o, parseStacktrace as p, setSafeTimers as s }; |
| function isMockFunction(fn) { | ||
| return typeof fn === "function" && "_isMockFunction" in fn && fn._isMockFunction === true; | ||
| } | ||
| const MOCK_RESTORE = /* @__PURE__ */ new Set(); | ||
| // Jest keeps the state in a separate WeakMap which is good for memory, | ||
| // but it makes the state slower to access and return different values | ||
| // if you stored it before calling `mockClear` where it will be recreated | ||
| const REGISTERED_MOCKS = /* @__PURE__ */ new Set(); | ||
| const MOCK_CONFIGS = /* @__PURE__ */ new WeakMap(); | ||
| function createMockInstance(options = {}) { | ||
| const { originalImplementation, restore, mockImplementation, resetToMockImplementation, resetToMockName } = options; | ||
| if (restore) MOCK_RESTORE.add(restore); | ||
| const config = getDefaultConfig(originalImplementation); | ||
| const state = getDefaultState(); | ||
| const mock = createMock({ | ||
| config, | ||
| state, | ||
| ...options | ||
| }); | ||
| const mockLength = (mockImplementation || originalImplementation)?.length ?? 0; | ||
| Object.defineProperty(mock, "length", { | ||
| writable: true, | ||
| enumerable: false, | ||
| value: mockLength, | ||
| configurable: true | ||
| }); | ||
| // inherit the default name so it appears in snapshots and logs | ||
| // this is used by `vi.spyOn()` for better debugging. | ||
| // when `vi.fn()` is called, we just use the default string | ||
| if (resetToMockName) config.mockName = mock.name || "vi.fn()"; | ||
| MOCK_CONFIGS.set(mock, config); | ||
| REGISTERED_MOCKS.add(mock); | ||
| mock._isMockFunction = true; | ||
| mock.getMockImplementation = () => { | ||
| // Jest only returns `config.mockImplementation` here, | ||
| // but we think it makes sense to return what the next function will be called | ||
| return config.onceMockImplementations[0] || config.mockImplementation; | ||
| }; | ||
| Object.defineProperty(mock, "mock", { | ||
| configurable: false, | ||
| enumerable: true, | ||
| writable: false, | ||
| value: state | ||
| }); | ||
| mock.mockImplementation = function mockImplementation(implementation) { | ||
| config.mockImplementation = implementation; | ||
| return mock; | ||
| }; | ||
| mock.mockImplementationOnce = function mockImplementationOnce(implementation) { | ||
| config.onceMockImplementations.push(implementation); | ||
| return mock; | ||
| }; | ||
| mock.withImplementation = function withImplementation(implementation, callback) { | ||
| const previousImplementation = config.mockImplementation; | ||
| const previousOnceImplementations = config.onceMockImplementations; | ||
| const reset = () => { | ||
| config.mockImplementation = previousImplementation; | ||
| config.onceMockImplementations = previousOnceImplementations; | ||
| }; | ||
| config.mockImplementation = implementation; | ||
| config.onceMockImplementations = []; | ||
| const returnValue = callback(); | ||
| if (typeof returnValue === "object" && typeof returnValue?.then === "function") return returnValue.then(() => { | ||
| reset(); | ||
| return mock; | ||
| }); | ||
| else reset(); | ||
| return mock; | ||
| }; | ||
| mock.mockReturnThis = function mockReturnThis() { | ||
| return mock.mockImplementation(function() { | ||
| return this; | ||
| }); | ||
| }; | ||
| mock.mockReturnValue = function mockReturnValue(value) { | ||
| return mock.mockImplementation(function() { | ||
| if (new.target) throwConstructorError("mockReturnValue"); | ||
| return value; | ||
| }); | ||
| }; | ||
| mock.mockReturnValueOnce = function mockReturnValueOnce(value) { | ||
| return mock.mockImplementationOnce(function() { | ||
| if (new.target) throwConstructorError("mockReturnValueOnce"); | ||
| return value; | ||
| }); | ||
| }; | ||
| mock.mockThrow = function mockThrow(value) { | ||
| // eslint-disable-next-line prefer-arrow-callback | ||
| return mock.mockImplementation(function() { | ||
| throw value; | ||
| }); | ||
| }; | ||
| mock.mockThrowOnce = function mockThrowOnce(value) { | ||
| // eslint-disable-next-line prefer-arrow-callback | ||
| return mock.mockImplementationOnce(function() { | ||
| throw value; | ||
| }); | ||
| }; | ||
| mock.mockResolvedValue = function mockResolvedValue(value) { | ||
| return mock.mockImplementation(function() { | ||
| if (new.target) throwConstructorError("mockResolvedValue"); | ||
| return Promise.resolve(value); | ||
| }); | ||
| }; | ||
| mock.mockResolvedValueOnce = function mockResolvedValueOnce(value) { | ||
| return mock.mockImplementationOnce(function() { | ||
| if (new.target) throwConstructorError("mockResolvedValueOnce"); | ||
| return Promise.resolve(value); | ||
| }); | ||
| }; | ||
| mock.mockRejectedValue = function mockRejectedValue(value) { | ||
| return mock.mockImplementation(function() { | ||
| if (new.target) throwConstructorError("mockRejectedValue"); | ||
| return Promise.reject(value); | ||
| }); | ||
| }; | ||
| mock.mockRejectedValueOnce = function mockRejectedValueOnce(value) { | ||
| return mock.mockImplementationOnce(function() { | ||
| if (new.target) throwConstructorError("mockRejectedValueOnce"); | ||
| return Promise.reject(value); | ||
| }); | ||
| }; | ||
| mock.mockClear = function mockClear() { | ||
| state.calls = []; | ||
| state.contexts = []; | ||
| state.instances = []; | ||
| state.invocationCallOrder = []; | ||
| state.results = []; | ||
| state.settledResults = []; | ||
| return mock; | ||
| }; | ||
| mock.mockReset = function mockReset() { | ||
| mock.mockClear(); | ||
| config.mockImplementation = resetToMockImplementation ? mockImplementation : void 0; | ||
| config.mockName = resetToMockName ? mock.name || "vi.fn()" : "vi.fn()"; | ||
| config.onceMockImplementations = []; | ||
| return mock; | ||
| }; | ||
| mock.mockRestore = function mockRestore() { | ||
| mock.mockReset(); | ||
| return restore?.(); | ||
| }; | ||
| mock.mockName = function mockName(name) { | ||
| if (typeof name === "string") config.mockName = name; | ||
| return mock; | ||
| }; | ||
| mock.getMockName = function getMockName() { | ||
| return config.mockName || "vi.fn()"; | ||
| }; | ||
| if (Symbol.dispose) mock[Symbol.dispose] = () => mock.mockRestore(); | ||
| if (mockImplementation) mock.mockImplementation(mockImplementation); | ||
| return mock; | ||
| } | ||
| function fn(originalImplementation) { | ||
| // if the function is already a mock, just return the same function, | ||
| // similarly to how vi.spyOn() works | ||
| if (originalImplementation != null && isMockFunction(originalImplementation)) return originalImplementation; | ||
| return createMockInstance({ | ||
| mockImplementation: originalImplementation, | ||
| resetToMockImplementation: true | ||
| }); | ||
| } | ||
| function spyOn(object, key, accessor) { | ||
| assert(object != null, "The vi.spyOn() function could not find an object to spy upon. The first argument must be defined."); | ||
| assert(typeof object === "object" || typeof object === "function", "Vitest cannot spy on a primitive value."); | ||
| const [originalDescriptorObject, originalDescriptor] = getDescriptor(object, key) || []; | ||
| assert(originalDescriptor || key in object, `The property "${String(key)}" is not defined on the ${typeof object}.`); | ||
| let accessType = accessor || "value"; | ||
| let ssr = false; | ||
| // vite ssr support - actual function is stored inside a getter | ||
| if (accessType === "value" && originalDescriptor && originalDescriptor.value == null && originalDescriptor.get) { | ||
| accessType = "get"; | ||
| ssr = true; | ||
| } | ||
| let original; | ||
| if (originalDescriptor) { | ||
| original = originalDescriptor[accessType]; | ||
| // weird Proxy edge case where descriptor's value is undefined, | ||
| // but there's still a value on the object when called | ||
| // https://github.com/vitest-dev/vitest/issues/9439 | ||
| if (original == null && accessType === "value") original = object[key]; | ||
| } else if (accessType !== "value") original = () => object[key]; | ||
| else original = object[key]; | ||
| const originalImplementation = ssr && original ? original() : original; | ||
| const originalType = typeof originalImplementation; | ||
| assert( | ||
| // allow only functions | ||
| originalType === "function" || accessType !== "value" && original == null, | ||
| `vi.spyOn() can only spy on a function. Received ${originalType}.` | ||
| ); | ||
| if (isMockFunction(originalImplementation)) return originalImplementation; | ||
| const reassign = (cb) => { | ||
| const { value, ...desc } = originalDescriptor || { | ||
| configurable: true, | ||
| writable: true | ||
| }; | ||
| if (accessType !== "value") delete desc.writable; | ||
| desc[accessType] = cb; | ||
| Object.defineProperty(object, key, desc); | ||
| }; | ||
| const restore = () => { | ||
| // if method is defined on the prototype, we can just remove it from | ||
| // the current object instead of redefining a copy of it | ||
| if (originalDescriptorObject !== object) Reflect.deleteProperty(object, key); | ||
| else if (originalDescriptor && !original) Object.defineProperty(object, key, originalDescriptor); | ||
| else reassign(original); | ||
| }; | ||
| const mock = createMockInstance({ | ||
| restore, | ||
| originalImplementation, | ||
| resetToMockName: true | ||
| }); | ||
| try { | ||
| reassign(ssr ? () => mock : mock); | ||
| } catch (error) { | ||
| if (error instanceof TypeError && Symbol.toStringTag && object[Symbol.toStringTag] === "Module" && (error.message.includes("Cannot redefine property") || error.message.includes("Cannot replace module namespace") || error.message.includes("can't redefine non-configurable property"))) throw new TypeError(`Cannot spy on export "${String(key)}". Module namespace is not configurable in ESM. See: https://vitest.dev/guide/browser/#limitations`, { cause: error }); | ||
| throw error; | ||
| } | ||
| return mock; | ||
| } | ||
| function getDescriptor(obj, method) { | ||
| const objDescriptor = Object.getOwnPropertyDescriptor(obj, method); | ||
| if (objDescriptor) return [obj, objDescriptor]; | ||
| let currentProto = Object.getPrototypeOf(obj); | ||
| while (currentProto !== null) { | ||
| const descriptor = Object.getOwnPropertyDescriptor(currentProto, method); | ||
| if (descriptor) return [currentProto, descriptor]; | ||
| currentProto = Object.getPrototypeOf(currentProto); | ||
| } | ||
| } | ||
| function assert(condition, message) { | ||
| if (!condition) throw new Error(message); | ||
| } | ||
| let invocationCallCounter = 1; | ||
| function createMock({ state, config, name: mockName, prototypeState, prototypeConfig, keepMembersImplementation, mockImplementation, prototypeMembers = [] }) { | ||
| const original = config.mockOriginal; | ||
| const pseudoOriginal = mockImplementation; | ||
| const name = mockName || original?.name || "Mock"; | ||
| const namedObject = { [name]: (function(...args) { | ||
| registerCalls(args, state, prototypeState); | ||
| registerInvocationOrder(invocationCallCounter++, state, prototypeState); | ||
| const result = { | ||
| type: "incomplete", | ||
| value: void 0 | ||
| }; | ||
| const settledResult = { | ||
| type: "incomplete", | ||
| value: void 0 | ||
| }; | ||
| registerResult(result, state, prototypeState); | ||
| registerSettledResult(settledResult, state, prototypeState); | ||
| const context = new.target ? void 0 : this; | ||
| const [instanceIndex, instancePrototypeIndex] = registerInstance(context, state, prototypeState); | ||
| const [contextIndex, contextPrototypeIndex] = registerContext(context, state, prototypeState); | ||
| const implementation = config.onceMockImplementations.shift() || config.mockImplementation || prototypeConfig?.onceMockImplementations.shift() || prototypeConfig?.mockImplementation || original || function() {}; | ||
| let returnValue; | ||
| let thrownValue; | ||
| let didThrow = false; | ||
| try { | ||
| if (new.target) { | ||
| returnValue = Reflect.construct(implementation, args, new.target); | ||
| // jest calls this before the implementation, but we have to resolve this _after_ | ||
| // because we cannot do it before the `Reflect.construct` called the custom implementation. | ||
| // fortunately, the constructor is always an empty function because `prototypeMethods` | ||
| // are only used by the automocker, so this doesn't matter | ||
| for (const prop of prototypeMembers) { | ||
| const prototypeMock = returnValue[prop]; | ||
| // the method was overridden because of inheritance, ignore it | ||
| // eslint-disable-next-line ts/no-use-before-define | ||
| if (prototypeMock !== mock.prototype[prop]) continue; | ||
| const isMock = isMockFunction(prototypeMock); | ||
| const prototypeState = isMock ? prototypeMock.mock : void 0; | ||
| const prototypeConfig = isMock ? MOCK_CONFIGS.get(prototypeMock) : void 0; | ||
| returnValue[prop] = createMockInstance({ | ||
| originalImplementation: keepMembersImplementation ? prototypeConfig?.mockOriginal : void 0, | ||
| prototypeState, | ||
| prototypeConfig, | ||
| keepMembersImplementation | ||
| }); | ||
| } | ||
| } else returnValue = implementation.apply(this, args); | ||
| } catch (error) { | ||
| thrownValue = error; | ||
| didThrow = true; | ||
| if (error instanceof TypeError && error.message.includes("is not a constructor")) console.warn(`[vitest] The ${namedObject[name].getMockName()} mock did not use 'function' or 'class' in its implementation, see https://vitest.dev/api/vi#vi-spyon for examples.`); | ||
| throw error; | ||
| } finally { | ||
| if (didThrow) { | ||
| result.type = "throw"; | ||
| result.value = thrownValue; | ||
| settledResult.type = "rejected"; | ||
| settledResult.value = thrownValue; | ||
| } else { | ||
| result.type = "return"; | ||
| result.value = returnValue; | ||
| if (new.target) { | ||
| state.contexts[contextIndex - 1] = returnValue; | ||
| state.instances[instanceIndex - 1] = returnValue; | ||
| if (contextPrototypeIndex != null && prototypeState) prototypeState.contexts[contextPrototypeIndex - 1] = returnValue; | ||
| if (instancePrototypeIndex != null && prototypeState) prototypeState.instances[instancePrototypeIndex - 1] = returnValue; | ||
| } | ||
| if (returnValue instanceof Promise) returnValue.then((settledValue) => { | ||
| settledResult.type = "fulfilled"; | ||
| settledResult.value = settledValue; | ||
| }, (rejectedValue) => { | ||
| settledResult.type = "rejected"; | ||
| settledResult.value = rejectedValue; | ||
| }); | ||
| else { | ||
| settledResult.type = "fulfilled"; | ||
| settledResult.value = returnValue; | ||
| } | ||
| } | ||
| } | ||
| return returnValue; | ||
| }) }; | ||
| const mock = namedObject[name]; | ||
| const copyPropertiesFrom = original || pseudoOriginal; | ||
| if (copyPropertiesFrom) copyOriginalStaticProperties(mock, copyPropertiesFrom); | ||
| return mock; | ||
| } | ||
| function registerCalls(args, state, prototypeState) { | ||
| state.calls.push(args); | ||
| prototypeState?.calls.push(args); | ||
| } | ||
| function registerInvocationOrder(order, state, prototypeState) { | ||
| state.invocationCallOrder.push(order); | ||
| prototypeState?.invocationCallOrder.push(order); | ||
| } | ||
| function registerResult(result, state, prototypeState) { | ||
| state.results.push(result); | ||
| prototypeState?.results.push(result); | ||
| } | ||
| function registerSettledResult(result, state, prototypeState) { | ||
| state.settledResults.push(result); | ||
| prototypeState?.settledResults.push(result); | ||
| } | ||
| function registerInstance(instance, state, prototypeState) { | ||
| return [state.instances.push(instance), prototypeState?.instances.push(instance)]; | ||
| } | ||
| function registerContext(context, state, prototypeState) { | ||
| return [state.contexts.push(context), prototypeState?.contexts.push(context)]; | ||
| } | ||
| function copyOriginalStaticProperties(mock, original) { | ||
| const { properties, descriptors } = getAllProperties(original); | ||
| for (const key of properties) { | ||
| const descriptor = descriptors[key]; | ||
| if (getDescriptor(mock, key)) continue; | ||
| Object.defineProperty(mock, key, descriptor); | ||
| } | ||
| } | ||
| const ignoreProperties = new Set([ | ||
| "length", | ||
| "name", | ||
| "prototype", | ||
| Symbol.for("nodejs.util.promisify.custom") | ||
| ]); | ||
| function getAllProperties(original) { | ||
| const properties = /* @__PURE__ */ new Set(); | ||
| const descriptors = {}; | ||
| while (original && original !== Object.prototype && original !== Function.prototype) { | ||
| const ownProperties = [...Object.getOwnPropertyNames(original), ...Object.getOwnPropertySymbols(original)]; | ||
| for (const prop of ownProperties) { | ||
| if (descriptors[prop] || ignoreProperties.has(prop)) continue; | ||
| properties.add(prop); | ||
| descriptors[prop] = Object.getOwnPropertyDescriptor(original, prop); | ||
| } | ||
| original = Object.getPrototypeOf(original); | ||
| } | ||
| return { | ||
| properties, | ||
| descriptors | ||
| }; | ||
| } | ||
| function getDefaultConfig(original) { | ||
| return { | ||
| mockImplementation: void 0, | ||
| mockOriginal: original, | ||
| mockName: "vi.fn()", | ||
| onceMockImplementations: [] | ||
| }; | ||
| } | ||
| function getDefaultState() { | ||
| const state = { | ||
| calls: [], | ||
| contexts: [], | ||
| instances: [], | ||
| invocationCallOrder: [], | ||
| settledResults: [], | ||
| results: [], | ||
| get lastCall() { | ||
| return state.calls.at(-1); | ||
| } | ||
| }; | ||
| return state; | ||
| } | ||
| function restoreAllMocks() { | ||
| for (const restore of MOCK_RESTORE) restore(); | ||
| MOCK_RESTORE.clear(); | ||
| } | ||
| function clearAllMocks() { | ||
| REGISTERED_MOCKS.forEach((mock) => mock.mockClear()); | ||
| } | ||
| function resetAllMocks() { | ||
| REGISTERED_MOCKS.forEach((mock) => mock.mockReset()); | ||
| } | ||
| function throwConstructorError(shorthand) { | ||
| throw new TypeError(`Cannot use \`${shorthand}\` when called with \`new\`. Use \`mockImplementation\` with a \`class\` keyword instead. See https://vitest.dev/api/mock#class-support for more information.`); | ||
| } | ||
| var spyModule = /*#__PURE__*/Object.freeze({ | ||
| __proto__: null, | ||
| clearAllMocks: clearAllMocks, | ||
| createMockInstance: createMockInstance, | ||
| fn: fn, | ||
| isMockFunction: isMockFunction, | ||
| resetAllMocks: resetAllMocks, | ||
| restoreAllMocks: restoreAllMocks, | ||
| spyOn: spyOn | ||
| }); | ||
| export { spyOn as a, resetAllMocks as b, clearAllMocks as c, createMockInstance as d, fn as f, isMockFunction as i, restoreAllMocks as r, spyModule as s }; |
| import { ba as SnapshotState, d as Test, bb as PromisifyAssertion, bc as Tester, bd as Plugin, a1 as BenchResult, F as File } from './config.d.DsC1jkby.js'; | ||
| interface SnapshotMatcher<T> { | ||
| <U extends { [P in keyof T] : any }>(snapshot: Partial<U>, hint?: string): void; | ||
| (hint?: string): void; | ||
| } | ||
| interface InlineSnapshotMatcher<T> { | ||
| <U extends { [P in keyof T] : any }>(properties: Partial<U>, snapshot?: string, hint?: string): void; | ||
| (hint?: string): void; | ||
| } | ||
| declare module "vitest" { | ||
| interface MatcherState { | ||
| environment: string; | ||
| snapshotState: SnapshotState; | ||
| task?: Readonly<Test>; | ||
| } | ||
| interface ExpectPollOptions { | ||
| interval?: number; | ||
| timeout?: number; | ||
| message?: string; | ||
| } | ||
| interface ExpectStatic { | ||
| assert: Chai.AssertStatic; | ||
| unreachable: (message?: string) => never; | ||
| soft: <T>(actual: T, message?: string) => Assertion<T>; | ||
| poll: <T>(actual: (options: { | ||
| signal: AbortSignal; | ||
| }) => T, options?: ExpectPollOptions) => PromisifyAssertion<Awaited<T>>; | ||
| addEqualityTesters: (testers: Array<Tester>) => void; | ||
| assertions: (expected: number) => void; | ||
| hasAssertions: () => void; | ||
| addSnapshotSerializer: (plugin: Plugin) => void; | ||
| } | ||
| interface Assertion<T> { | ||
| matchSnapshot: SnapshotMatcher<T>; | ||
| toMatchSnapshot: SnapshotMatcher<T>; | ||
| toMatchInlineSnapshot: InlineSnapshotMatcher<T>; | ||
| /** | ||
| * Checks that an error thrown by a function matches a previously recorded snapshot. | ||
| * | ||
| * @param hint - Optional custom error message. | ||
| * | ||
| * @example | ||
| * expect(functionWithError).toThrowErrorMatchingSnapshot(); | ||
| */ | ||
| toThrowErrorMatchingSnapshot: (hint?: string) => void; | ||
| /** | ||
| * Checks that an error thrown by a function matches an inline snapshot within the test file. | ||
| * Useful for keeping snapshots close to the test code. | ||
| * | ||
| * @param snapshot - Optional inline snapshot string to match. | ||
| * @param hint - Optional custom error message. | ||
| * | ||
| * @example | ||
| * const throwError = () => { throw new Error('Error occurred') }; | ||
| * expect(throwError).toThrowErrorMatchingInlineSnapshot(`"Error occurred"`); | ||
| */ | ||
| toThrowErrorMatchingInlineSnapshot: (snapshot?: string, hint?: string) => void; | ||
| /** | ||
| * Compares the received value to a snapshot saved in a specified file. | ||
| * Useful for cases where snapshot content is large or needs to be shared across tests. | ||
| * | ||
| * @param filepath - Path to the snapshot file. | ||
| * @param hint - Optional custom error message. | ||
| * | ||
| * @example | ||
| * await expect(largeData).toMatchFileSnapshot('path/to/snapshot.json'); | ||
| */ | ||
| toMatchFileSnapshot: (filepath: string, hint?: string) => Promise<void>; | ||
| /** | ||
| * Asserts that a benchmark result is faster than another benchmark result. | ||
| * Compares mean latency — lower is faster. | ||
| * | ||
| * @example | ||
| * const result = await bench.compare( | ||
| * bench('lib1', () => { lib1() }), | ||
| * bench('lib2', () => { lib2() }), | ||
| * ) | ||
| * expect(result.get('lib1')).toBeFasterThan(result.get('lib2')) | ||
| * expect(result.get('lib1')).toBeFasterThan(result.get('lib2'), { delta: 0.1 }) | ||
| */ | ||
| toBeFasterThan: (expected: BenchResult, options?: { | ||
| delta?: number; | ||
| }) => void; | ||
| /** | ||
| * Asserts that a benchmark result is slower than another benchmark result. | ||
| * Compares mean latency — higher is slower. | ||
| * | ||
| * @example | ||
| * const result = await bench.compare( | ||
| * bench('lib1', () => { lib1() }), | ||
| * bench('lib2', () => { lib2() }), | ||
| * ) | ||
| * expect(result.get('lib2')).toBeSlowerThan(result.get('lib1')) | ||
| * expect(result.get('lib2')).toBeSlowerThan(result.get('lib1'), { delta: 0.2 }) | ||
| */ | ||
| toBeSlowerThan: (expected: BenchResult, options?: { | ||
| delta?: number; | ||
| }) => void; | ||
| /** | ||
| * Ensures a `vi.when` chain has been exhausted. | ||
| * | ||
| * A chain is exhausted when at least one `calledWith` with an associated action (`then*`) has been registered | ||
| * and every registered behavior has been fully consumed. A chain with no registered | ||
| * behaviors, or with `calledWith` entries that have no associated `then*` actions, is never considered exhausted. | ||
| * | ||
| * @see {@link https://vitest.dev/api/expect#tohavebeenexhausted} | ||
| * | ||
| * @example | ||
| * const w = vi.when(spy).calledWith('hello').thenReturnOnce('HELLO') | ||
| * | ||
| * expect(w).not.toHaveBeenExhausted() | ||
| * | ||
| * expect(spy('hello')).toBe('HELLO') | ||
| * | ||
| * expect(w).toHaveBeenExhausted() | ||
| */ | ||
| toHaveBeenExhausted: () => void; | ||
| } | ||
| } | ||
| interface HashMeta { | ||
| typecheck?: boolean; | ||
| __vitest_label__?: string; | ||
| } | ||
| declare function createFileTask(filepath: string, root: string, projectName: string | undefined, pool?: string, viteEnvironment?: string, meta?: HashMeta): File; | ||
| /** | ||
| * Generate a unique ID for a file based on its path and project name | ||
| * @param file File relative to the root of the project to keep ID the same between different machines | ||
| * @param projectName The name of the test project | ||
| */ | ||
| declare function generateFileHash(file: string, projectName: string | undefined, meta?: HashMeta): string; | ||
| export { createFileTask as c, generateFileHash as g }; |
| // src/index.ts | ||
| var b = { | ||
| reset: [0, 0], | ||
| bold: [1, 22, "\x1B[22m\x1B[1m"], | ||
| dim: [2, 22, "\x1B[22m\x1B[2m"], | ||
| italic: [3, 23], | ||
| underline: [4, 24], | ||
| inverse: [7, 27], | ||
| hidden: [8, 28], | ||
| strikethrough: [9, 29], | ||
| black: [30, 39], | ||
| red: [31, 39], | ||
| green: [32, 39], | ||
| yellow: [33, 39], | ||
| blue: [34, 39], | ||
| magenta: [35, 39], | ||
| cyan: [36, 39], | ||
| white: [37, 39], | ||
| gray: [90, 39], | ||
| bgBlack: [40, 49], | ||
| bgRed: [41, 49], | ||
| bgGreen: [42, 49], | ||
| bgYellow: [43, 49], | ||
| bgBlue: [44, 49], | ||
| bgMagenta: [45, 49], | ||
| bgCyan: [46, 49], | ||
| bgWhite: [47, 49], | ||
| blackBright: [90, 39], | ||
| redBright: [91, 39], | ||
| greenBright: [92, 39], | ||
| yellowBright: [93, 39], | ||
| blueBright: [94, 39], | ||
| magentaBright: [95, 39], | ||
| cyanBright: [96, 39], | ||
| whiteBright: [97, 39], | ||
| bgBlackBright: [100, 49], | ||
| bgRedBright: [101, 49], | ||
| bgGreenBright: [102, 49], | ||
| bgYellowBright: [103, 49], | ||
| bgBlueBright: [104, 49], | ||
| bgMagentaBright: [105, 49], | ||
| bgCyanBright: [106, 49], | ||
| bgWhiteBright: [107, 49] | ||
| }; | ||
| function i(e) { | ||
| return String(e); | ||
| } | ||
| i.open = ""; | ||
| i.close = ""; | ||
| function p() { | ||
| let e = { | ||
| isColorSupported: false, | ||
| reset: i | ||
| }; | ||
| for (let r in b) | ||
| e[r] = i; | ||
| return e; | ||
| } | ||
| function B() { | ||
| let e = typeof process != "undefined" ? process : void 0, r = (e == null ? void 0 : e.env) || {}, a = r.FORCE_TTY !== "false", l = (e == null ? void 0 : e.argv) || []; | ||
| return !("NO_COLOR" in r || l.includes("--no-color")) && ("FORCE_COLOR" in r || l.includes("--color") || (e == null ? void 0 : e.platform) === "win32" || a && r.TERM !== "dumb" || "CI" in r) || typeof window != "undefined" && !!window.chrome; | ||
| } | ||
| function C({ force: e } = {}) { | ||
| let r = e || B(), a = (t, o, u, n) => { | ||
| let g = "", s = 0; | ||
| do | ||
| g += t.substring(s, n) + u, s = n + o.length, n = t.indexOf(o, s); | ||
| while (~n); | ||
| return g + t.substring(s); | ||
| }, l = (t, o, u = t) => { | ||
| let n = (g) => { | ||
| let s = String(g), h = s.indexOf(o, t.length); | ||
| return ~h ? t + a(s, o, u, h) + o : t + s + o; | ||
| }; | ||
| return n.open = t, n.close = o, n; | ||
| }, c = { | ||
| isColorSupported: r | ||
| }, f = (t) => `\x1B[${t}m`; | ||
| for (let t in b) { | ||
| let o = b[t]; | ||
| c[t] = r ? l( | ||
| f(o[0]), | ||
| f(o[1]), | ||
| o[2] | ||
| ) : i; | ||
| } | ||
| return c; | ||
| } | ||
| var d = C(); | ||
| function m() { | ||
| Object.assign(d, p()); | ||
| } | ||
| var y = d; | ||
| export { m, y }; |
| import { stripVTControlCharacters } from 'node:util'; | ||
| import { t as truncateString$1 } from './display.CYwyMF4S.js'; | ||
| import { i as isAbsolute, a as relative, d as dirname, b as basename, s as slash } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { y } from './tinyrainbow.Ht9iggcq.js'; | ||
| const F_RIGHT = "→"; | ||
| const F_DOWN = "↓"; | ||
| const F_DOWN_RIGHT = "↳"; | ||
| const F_POINTER = "❯"; | ||
| const F_DOT = "·"; | ||
| const F_CHECK = "✓"; | ||
| const F_CROSS = "×"; | ||
| const F_LONG_DASH = "⎯"; | ||
| const F_TODO = "□"; | ||
| const F_TREE_NODE_MIDDLE = "├──"; | ||
| const F_TREE_NODE_END = "└──"; | ||
| const pointer = y.yellow(F_POINTER); | ||
| const skipped = y.dim(y.gray(F_DOWN)); | ||
| const todo = y.dim(y.gray(F_TODO)); | ||
| const benchmarkPass = y.green(F_DOT); | ||
| const testPass = y.green(F_CHECK); | ||
| const taskFail = y.red(F_CROSS); | ||
| const suiteFail = y.red(F_POINTER); | ||
| const pending = y.gray("·"); | ||
| const separator = y.dim(" > "); | ||
| const labelDefaultColors = [ | ||
| y.bgYellow, | ||
| y.bgCyan, | ||
| y.bgGreen, | ||
| y.bgMagenta | ||
| ]; | ||
| function getCols(delta = 0) { | ||
| let length = process.stdout?.columns; | ||
| if (!length || Number.isNaN(length)) length = 30; | ||
| return Math.max(length + delta, 0); | ||
| } | ||
| function errorBanner(message) { | ||
| return divider(y.bold(y.bgRed(` ${message} `)), null, null, y.red); | ||
| } | ||
| function divider(text, left, right, color) { | ||
| const cols = getCols(); | ||
| const c = color || ((text) => text); | ||
| if (text) { | ||
| const textLength = stripVTControlCharacters(text).length; | ||
| if (left == null && right != null) left = cols - textLength - right; | ||
| else { | ||
| left = left ?? Math.floor((cols - textLength) / 2); | ||
| right = cols - textLength - left; | ||
| } | ||
| left = Math.max(0, left); | ||
| right = Math.max(0, right); | ||
| return `${c(F_LONG_DASH.repeat(left))}${text}${c(F_LONG_DASH.repeat(right))}`; | ||
| } | ||
| return F_LONG_DASH.repeat(cols); | ||
| } | ||
| function formatTestPath(root, path) { | ||
| if (isAbsolute(path)) path = relative(root, path); | ||
| const dir = dirname(path); | ||
| const ext = path.match(/(\.(spec|test)\.[cm]?[tj]sx?)$/)?.[0] || ""; | ||
| const base = basename(path, ext); | ||
| return slash(y.dim(`${dir}/`) + y.bold(base)) + y.dim(ext); | ||
| } | ||
| function renderSnapshotSummary(rootDir, snapshots) { | ||
| const summary = []; | ||
| if (snapshots.added) summary.push(y.bold(y.green(`${snapshots.added} written`))); | ||
| if (snapshots.unmatched) summary.push(y.bold(y.red(`${snapshots.unmatched} failed`))); | ||
| if (snapshots.updated) summary.push(y.bold(y.green(`${snapshots.updated} updated `))); | ||
| if (snapshots.filesRemoved) if (snapshots.didUpdate) summary.push(y.bold(y.green(`${snapshots.filesRemoved} files removed `))); | ||
| else summary.push(y.bold(y.yellow(`${snapshots.filesRemoved} files obsolete `))); | ||
| if (snapshots.filesRemovedList && snapshots.filesRemovedList.length) { | ||
| const [head, ...tail] = snapshots.filesRemovedList; | ||
| summary.push(`${y.gray(F_DOWN_RIGHT)} ${formatTestPath(rootDir, head)}`); | ||
| tail.forEach((key) => { | ||
| summary.push(` ${y.gray(F_DOT)} ${formatTestPath(rootDir, key)}`); | ||
| }); | ||
| } | ||
| if (snapshots.unchecked) { | ||
| if (snapshots.didUpdate) summary.push(y.bold(y.green(`${snapshots.unchecked} removed`))); | ||
| else summary.push(y.bold(y.yellow(`${snapshots.unchecked} obsolete`))); | ||
| snapshots.uncheckedKeysByFile.forEach((uncheckedFile) => { | ||
| summary.push(`${y.gray(F_DOWN_RIGHT)} ${formatTestPath(rootDir, uncheckedFile.filePath)}`); | ||
| uncheckedFile.keys.forEach((key) => summary.push(` ${y.gray(F_DOT)} ${key}`)); | ||
| }); | ||
| } | ||
| return summary; | ||
| } | ||
| function countTestErrors(tasks) { | ||
| return tasks.reduce((c, i) => c + (i.result?.errors?.length || 0), 0); | ||
| } | ||
| function getStateString(tasks, name = "tests", showTotal = true) { | ||
| if (tasks.length === 0) return y.dim(`no ${name}`); | ||
| const passed = tasks.reduce((acc, i) => { | ||
| // Exclude expected failures from passed count | ||
| if (i.result?.state === "pass" && i.type === "test" && i.fails) return acc; | ||
| return i.result?.state === "pass" ? acc + 1 : acc; | ||
| }, 0); | ||
| const failed = tasks.reduce((acc, i) => i.result?.state === "fail" ? acc + 1 : acc, 0); | ||
| const skipped = tasks.reduce((acc, i) => i.mode === "skip" ? acc + 1 : acc, 0); | ||
| const todo = tasks.reduce((acc, i) => i.mode === "todo" ? acc + 1 : acc, 0); | ||
| const expectedFail = tasks.reduce((acc, i) => { | ||
| // Count tests that are marked as .fails and passed (which means they failed as expected) | ||
| if (i.result?.state === "pass" && i.type === "test" && i.fails) return acc + 1; | ||
| return acc; | ||
| }, 0); | ||
| return [ | ||
| failed ? y.bold(y.red(`${failed} failed`)) : null, | ||
| passed ? y.bold(y.green(`${passed} passed`)) : null, | ||
| expectedFail ? y.cyan(`${expectedFail} expected fail`) : null, | ||
| skipped ? y.yellow(`${skipped} skipped`) : null, | ||
| todo ? y.gray(`${todo} todo`) : null | ||
| ].filter(Boolean).join(y.dim(" | ")) + (showTotal ? y.gray(` (${tasks.length})`) : ""); | ||
| } | ||
| function getStateSymbol(task) { | ||
| if (task.mode === "todo") return todo; | ||
| if (task.mode === "skip") return skipped; | ||
| if (!task.result) return pending; | ||
| if (task.result.state === "run" || task.result.state === "queued") { | ||
| if (task.type === "suite") return pointer; | ||
| } | ||
| if (task.result.state === "pass") return task.meta?.benchmark ? benchmarkPass : testPass; | ||
| if (task.result.state === "fail") return task.type === "suite" ? suiteFail : taskFail; | ||
| return " "; | ||
| } | ||
| function formatTimeString(date) { | ||
| return date.toTimeString().split(" ")[0]; | ||
| } | ||
| function formatTime(time) { | ||
| if (time > 1e3) return `${(time / 1e3).toFixed(2)}s`; | ||
| return `${Math.round(time)}ms`; | ||
| } | ||
| function formatProjectName(project, suffix = " ") { | ||
| if (!project?.name) return ""; | ||
| if (!y.isColorSupported) return `|${project.name}|${suffix}`; | ||
| let background = project.color && y[`bg${capitalize(project.color)}`]; | ||
| if (!background) background = labelDefaultColors[project.name.split("").reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0) % labelDefaultColors.length]; | ||
| return y.black(background(` ${project.name} `)) + suffix; | ||
| } | ||
| function withLabel(color, label, message) { | ||
| const bgColor = `bg${color.charAt(0).toUpperCase()}${color.slice(1)}`; | ||
| return `${y.bold(y.black(y[bgColor](` ${label} `)))} ${message ? y[color](message) : ""}`; | ||
| } | ||
| function padSummaryTitle(str) { | ||
| return y.dim(`${str.padStart(11)} `); | ||
| } | ||
| function truncateString(text, maxLength) { | ||
| return truncateString$1(stripVTControlCharacters(text), maxLength); | ||
| } | ||
| function capitalize(text) { | ||
| return `${text[0].toUpperCase()}${text.slice(1)}`; | ||
| } | ||
| /** | ||
| * Returns the singular or plural form of a word based on the count. | ||
| */ | ||
| function noun(count, singular, plural) { | ||
| if (count === 1) return singular; | ||
| return plural; | ||
| } | ||
| var utils = /*#__PURE__*/Object.freeze({ | ||
| __proto__: null, | ||
| benchmarkPass: benchmarkPass, | ||
| countTestErrors: countTestErrors, | ||
| divider: divider, | ||
| errorBanner: errorBanner, | ||
| formatProjectName: formatProjectName, | ||
| formatTestPath: formatTestPath, | ||
| formatTime: formatTime, | ||
| formatTimeString: formatTimeString, | ||
| getStateString: getStateString, | ||
| getStateSymbol: getStateSymbol, | ||
| noun: noun, | ||
| padSummaryTitle: padSummaryTitle, | ||
| pending: pending, | ||
| pointer: pointer, | ||
| renderSnapshotSummary: renderSnapshotSummary, | ||
| separator: separator, | ||
| skipped: skipped, | ||
| suiteFail: suiteFail, | ||
| taskFail: taskFail, | ||
| testPass: testPass, | ||
| todo: todo, | ||
| truncateString: truncateString, | ||
| withLabel: withLabel | ||
| }); | ||
| export { F_POINTER as F, formatTimeString as a, taskFail as b, F_CHECK as c, divider as d, errorBanner as e, formatProjectName as f, F_DOWN_RIGHT as g, getStateSymbol as h, getStateString as i, formatTime as j, countTestErrors as k, F_TREE_NODE_END as l, F_TREE_NODE_MIDDLE as m, noun as n, F_RIGHT as o, padSummaryTitle as p, renderSnapshotSummary as r, separator as s, truncateString as t, utils as u, withLabel as w }; |
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import vm, { isContext, runInContext } from 'node:vm'; | ||
| import { l as loadEnvironment, a as listenForErrors, e as emitModuleRunner } from './init.CfiYZpFg.js'; | ||
| import { distDir } from '../path.js'; | ||
| import { createCustomConsole } from './console.omGxyKMT.js'; | ||
| import fs__default from 'node:fs'; | ||
| import { createRequire, Module, isBuiltin } from 'node:module'; | ||
| import { d as dirname, b as basename, f as extname, C as CSS_LANGS_RE, h as KNOWN_ASSET_RE, t as toArray, k as splitFileAndPostfix, n as normalize, l as isBareImport, r as resolve } from './pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { l as lookupPackageScopeType } from './resolver.CERfsKE-.js'; | ||
| import { dirname as dirname$1 } from 'node:path'; | ||
| import { getDefaultRequestStubs } from '../module-evaluator.js'; | ||
| import { s as startVitestModuleRunner, V as VITEST_VM_CONTEXT_SYMBOL, c as createNodeImportMeta } from './index.DxR-nMjO.js'; | ||
| import { b as setupEnv } from './setup-common.vxjAyUtK.js'; | ||
| import { p as provideWorkerState } from './utils.DYj33du9.js'; | ||
| function interopCommonJsModule(interopDefault, mod) { | ||
| if (isPrimitive(mod) || Array.isArray(mod) || mod instanceof Promise) return { | ||
| keys: [], | ||
| moduleExports: {}, | ||
| defaultExport: mod | ||
| }; | ||
| if (interopDefault !== false && "__esModule" in mod && !isPrimitive(mod.default)) { | ||
| const defaultKets = Object.keys(mod.default); | ||
| const moduleKeys = Object.keys(mod); | ||
| const allKeys = new Set([...defaultKets, ...moduleKeys]); | ||
| allKeys.delete("default"); | ||
| return { | ||
| keys: Array.from(allKeys), | ||
| moduleExports: new Proxy(mod, { get(mod, prop) { | ||
| return mod[prop] ?? mod.default?.[prop]; | ||
| } }), | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| return { | ||
| keys: Object.keys(mod).filter((key) => key !== "default"), | ||
| moduleExports: mod, | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| function isPrimitive(obj) { | ||
| return !(obj != null && (typeof obj === "object" || typeof obj === "function")); | ||
| } | ||
| const SyntheticModule = vm.SyntheticModule; | ||
| const SourceTextModule = vm.SourceTextModule; | ||
| const _require = createRequire(import.meta.url); | ||
| const requiresCache = /* @__PURE__ */ new WeakMap(); | ||
| class CommonjsExecutor { | ||
| context; | ||
| requireCache = /* @__PURE__ */ new Map(); | ||
| publicRequireCache = this.createProxyCache(); | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| builtinCache = Object.create(null); | ||
| extensions = Object.create(null); | ||
| fs; | ||
| codeCache; | ||
| Module; | ||
| interopDefault; | ||
| constructor(options) { | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.codeCache = options.codeCache; | ||
| this.interopDefault = options.interopDefault; | ||
| const primitives = vm.runInContext("({ Object, Array, Error })", this.context); | ||
| // eslint-disable-next-line ts/no-this-alias | ||
| const executor = this; | ||
| this.Module = class Module$1 { | ||
| exports; | ||
| isPreloading = false; | ||
| id; | ||
| filename; | ||
| loaded; | ||
| parent; | ||
| children = []; | ||
| path; | ||
| paths = []; | ||
| constructor(id = "", parent) { | ||
| this.exports = primitives.Object.create(Object.prototype); | ||
| // in our case the path should always be resolved already | ||
| this.path = dirname(id); | ||
| this.id = id; | ||
| this.filename = id; | ||
| this.loaded = false; | ||
| this.parent = parent; | ||
| } | ||
| get require() { | ||
| const require = requiresCache.get(this); | ||
| if (require) return require; | ||
| const _require = Module$1.createRequire(this.id); | ||
| requiresCache.set(this, _require); | ||
| return _require; | ||
| } | ||
| static getSourceMapsSupport = () => ({ | ||
| enabled: false, | ||
| nodeModules: false, | ||
| generatedCode: false | ||
| }); | ||
| static setSourceMapsSupport = () => { | ||
| // noop | ||
| }; | ||
| static register = () => { | ||
| throw new Error(`[vitest] "register" is not available when running in Vitest.`); | ||
| }; | ||
| static registerHooks = () => { | ||
| throw new Error(`[vitest] "registerHooks" is not available when running in Vitest.`); | ||
| }; | ||
| _compile(code, filename) { | ||
| const cjsModule = Module$1.wrap(code); | ||
| const codeCache = executor.codeCache; | ||
| const cachedData = codeCache?.get(filename, cjsModule); | ||
| const script = new vm.Script(cjsModule, { | ||
| filename, | ||
| cachedData, | ||
| importModuleDynamically: options.importModuleDynamically | ||
| }); | ||
| if (cachedData && script.cachedDataRejected) codeCache.delete(filename); | ||
| // @ts-expect-error mark script with current identifier | ||
| script.identifier = filename; | ||
| const fn = script.runInContext(executor.context); | ||
| const __dirname = dirname(filename); | ||
| executor.requireCache.set(filename, this); | ||
| try { | ||
| fn(this.exports, this.require, this, filename, __dirname); | ||
| return this.exports; | ||
| } finally { | ||
| this.loaded = true; | ||
| // store after execution so the code cache carries the compiled | ||
| // module body, not only the lazily-parsed wrapper | ||
| codeCache?.store(filename, cjsModule, () => script.createCachedData()); | ||
| } | ||
| } | ||
| // exposed for external use, Node.js does the opposite | ||
| static _load = (request, parent, _isMain) => { | ||
| return Module$1.createRequire(parent?.filename ?? request)(request); | ||
| }; | ||
| static wrap = (script) => { | ||
| return Module$1.wrapper[0] + script + Module$1.wrapper[1]; | ||
| }; | ||
| static wrapper = new primitives.Array("(function (exports, require, module, __filename, __dirname) { ", "\n});"); | ||
| static builtinModules = Module.builtinModules; | ||
| static findSourceMap = Module.findSourceMap; | ||
| static SourceMap = Module.SourceMap; | ||
| static syncBuiltinESMExports = Module.syncBuiltinESMExports; | ||
| static _cache = executor.publicRequireCache; | ||
| static _extensions = executor.extensions; | ||
| static createRequire = (filename) => { | ||
| return executor.createRequire(filename); | ||
| }; | ||
| static runMain = () => { | ||
| throw new primitives.Error("[vitest] \"runMain\" is not implemented."); | ||
| }; | ||
| // @ts-expect-error not typed | ||
| static _resolveFilename = Module._resolveFilename; | ||
| // @ts-expect-error not typed | ||
| static _findPath = Module._findPath; | ||
| // @ts-expect-error not typed | ||
| static _initPaths = Module._initPaths; | ||
| // @ts-expect-error not typed | ||
| static _preloadModules = Module._preloadModules; | ||
| // @ts-expect-error not typed | ||
| static _resolveLookupPaths = Module._resolveLookupPaths; | ||
| // @ts-expect-error not typed | ||
| static globalPaths = Module.globalPaths; | ||
| static isBuiltin = Module.isBuiltin; | ||
| static constants = Module.constants; | ||
| static enableCompileCache = Module.enableCompileCache; | ||
| static getCompileCacheDir = Module.getCompileCacheDir; | ||
| static flushCompileCache = Module.flushCompileCache; | ||
| static stripTypeScriptTypes = Module.stripTypeScriptTypes; | ||
| static findPackageJSON = Module.findPackageJSON; | ||
| static Module = Module$1; | ||
| }; | ||
| this.extensions[".js"] = this.requireJs; | ||
| this.extensions[".json"] = this.requireJson; | ||
| } | ||
| requireJs = (m, filename) => { | ||
| const content = this.fs.readFile(filename); | ||
| m._compile(content, filename); | ||
| }; | ||
| requireJson = (m, filename) => { | ||
| const code = this.fs.readFile(filename); | ||
| m.exports = JSON.parse(code); | ||
| }; | ||
| static cjsConditions; | ||
| static getCjsConditions() { | ||
| if (!CommonjsExecutor.cjsConditions) CommonjsExecutor.cjsConditions = parseCjsConditions(process.execArgv, process.env.NODE_OPTIONS); | ||
| return CommonjsExecutor.cjsConditions; | ||
| } | ||
| createRequire = (filename) => { | ||
| const _require = createRequire(filename); | ||
| const resolve = (id, options) => { | ||
| return _require.resolve(id, { | ||
| ...options, | ||
| conditions: CommonjsExecutor.getCjsConditions() | ||
| }); | ||
| }; | ||
| const require = ((id) => { | ||
| const resolved = resolve(id); | ||
| if (extname(resolved) === ".node" || isBuiltin(resolved)) return this.requireCoreModule(resolved); | ||
| const module = new this.Module(resolved); | ||
| return this.loadCommonJSModule(module, resolved); | ||
| }); | ||
| require.resolve = resolve; | ||
| require.resolve.paths = _require.resolve.paths; | ||
| Object.defineProperty(require, "extensions", { | ||
| get: () => this.extensions, | ||
| set: () => {}, | ||
| configurable: true | ||
| }); | ||
| require.main = void 0; | ||
| require.cache = this.publicRequireCache; | ||
| return require; | ||
| }; | ||
| createProxyCache() { | ||
| return new Proxy(Object.create(null), { | ||
| defineProperty: () => true, | ||
| deleteProperty: () => true, | ||
| set: () => true, | ||
| get: (_, key) => this.requireCache.get(key), | ||
| has: (_, key) => this.requireCache.has(key), | ||
| ownKeys: () => Array.from(this.requireCache.keys()), | ||
| getOwnPropertyDescriptor() { | ||
| return { | ||
| configurable: true, | ||
| enumerable: true | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| // very naive implementation for Node.js require | ||
| loadCommonJSModule(module, filename) { | ||
| const cached = this.requireCache.get(filename); | ||
| if (cached) return cached.exports; | ||
| const extension = this.findLongestRegisteredExtension(filename); | ||
| (this.extensions[extension] || this.extensions[".js"])(module, filename); | ||
| return module.exports; | ||
| } | ||
| findLongestRegisteredExtension(filename) { | ||
| const name = basename(filename); | ||
| let currentExtension; | ||
| let index; | ||
| let startIndex = 0; | ||
| // eslint-disable-next-line no-cond-assign | ||
| while ((index = name.indexOf(".", startIndex)) !== -1) { | ||
| startIndex = index + 1; | ||
| if (index === 0) continue; | ||
| currentExtension = name.slice(index); | ||
| if (this.extensions[currentExtension]) return currentExtension; | ||
| } | ||
| return ".js"; | ||
| } | ||
| getCoreSyntheticModule(identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(identifier); | ||
| const keys = Object.keys(exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], () => { | ||
| for (const key of keys) module.setExport(key, exports$1[key]); | ||
| module.setExport("default", exports$1); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| getCjsSyntheticModule(path, identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(path); | ||
| // TODO: technically module should be parsed to find static exports, implement for strict mode in #2854 | ||
| const { keys, moduleExports, defaultExport } = interopCommonJsModule(this.interopDefault, exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], function() { | ||
| for (const key of keys) this.setExport(key, moduleExports[key]); | ||
| this.setExport("default", defaultExport); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| // TODO: use this in strict mode, when available in #2854 | ||
| // private _getNamedCjsExports(path: string): Set<string> { | ||
| // const cachedNamedExports = this.cjsNamedExportsMap.get(path) | ||
| // if (cachedNamedExports) { | ||
| // return cachedNamedExports | ||
| // } | ||
| // if (extname(path) === '.node') { | ||
| // const moduleExports = this.require(path) | ||
| // const namedExports = new Set(Object.keys(moduleExports)) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // return namedExports | ||
| // } | ||
| // const code = this.fs.readFile(path) | ||
| // const { exports, reexports } = parseCjs(code, path) | ||
| // const namedExports = new Set(exports) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // for (const reexport of reexports) { | ||
| // if (isNodeBuiltin(reexport)) { | ||
| // const exports = this.require(reexport) | ||
| // if (exports !== null && typeof exports === 'object') { | ||
| // for (const e of Object.keys(exports)) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // else { | ||
| // const require = this.createRequire(path) | ||
| // const resolved = require.resolve(reexport) | ||
| // const exports = this._getNamedCjsExports(resolved) | ||
| // for (const e of exports) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // return namedExports | ||
| // } | ||
| require(identifier) { | ||
| if (extname(identifier) === ".node" || isBuiltin(identifier)) return this.requireCoreModule(identifier); | ||
| const module = new this.Module(identifier); | ||
| return this.loadCommonJSModule(module, identifier); | ||
| } | ||
| requireCoreModule(identifier) { | ||
| const normalized = identifier.replace(/^node:/, ""); | ||
| if (this.builtinCache[normalized]) return this.builtinCache[normalized].exports; | ||
| const moduleExports = _require(identifier); | ||
| if (identifier === "node:module" || identifier === "module") { | ||
| const module = new this.Module("/module.js"); | ||
| module.exports = this.Module; | ||
| this.builtinCache[normalized] = module; | ||
| return module.exports; | ||
| } | ||
| this.builtinCache[normalized] = _require.cache[normalized]; | ||
| // TODO: should we wrap module to rethrow context errors? | ||
| return moduleExports; | ||
| } | ||
| } | ||
| // The "module-sync" exports condition (added in Node 22.12/20.19 when | ||
| // require(esm) was unflagged) can resolve to ESM files that our CJS | ||
| // vm.Script executor cannot handle. We exclude it by passing explicit | ||
| // CJS conditions to require.resolve (Node 22.12+). | ||
| // Must be a Set because Node's internal resolver calls conditions.has(). | ||
| // User-specified --conditions/-C flags are respected, except module-sync. | ||
| function parseCjsConditions(execArgv, nodeOptions) { | ||
| const conditions = [ | ||
| "node", | ||
| "require", | ||
| "node-addons" | ||
| ]; | ||
| const args = [...execArgv, ...nodeOptions?.split(/\s+/) ?? []]; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i]; | ||
| const eqMatch = arg.match(/^(?:--conditions|-C)=(.+)$/); | ||
| if (eqMatch) conditions.push(eqMatch[1]); | ||
| else if ((arg === "--conditions" || arg === "-C") && i + 1 < args.length) conditions.push(args[++i]); | ||
| } | ||
| return new Set(conditions.filter((c) => c !== "module-sync")); | ||
| } | ||
| const dataURIRegex = /^data:(?<mime>text\/javascript|application\/json|application\/wasm)(?:;(?<encoding>charset=utf-8|base64))?,(?<code>.*)$/; | ||
| class EsmExecutor { | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| esmLinkMap = /* @__PURE__ */ new WeakMap(); | ||
| context; | ||
| #httpIp = IPnumber("127.0.0.0"); | ||
| constructor(executor, options) { | ||
| this.executor = executor; | ||
| this.context = options.context; | ||
| } | ||
| async evaluateModule(m) { | ||
| if (m.status === "unlinked") this.esmLinkMap.set(m, m.link((identifier, referencer) => this.executor.resolveModule(identifier, referencer.identifier))); | ||
| await this.esmLinkMap.get(m); | ||
| if (m.status === "linked") await m.evaluate(); | ||
| return m; | ||
| } | ||
| async createEsModule(fileURL, getCode) { | ||
| const cached = this.moduleCache.get(fileURL); | ||
| if (cached) return cached; | ||
| const promise = this.loadEsModule(fileURL, getCode); | ||
| this.moduleCache.set(fileURL, promise); | ||
| return promise; | ||
| } | ||
| async loadEsModule(fileURL, getCode) { | ||
| const code = await getCode(); | ||
| // TODO: should not be allowed in strict mode, implement in #2854 | ||
| if (fileURL.endsWith(".json")) { | ||
| const m = new SyntheticModule(["default"], function() { | ||
| const result = JSON.parse(code); | ||
| this.setExport("default", result); | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| const codeCache = this.executor.codeCache; | ||
| const cachedData = codeCache?.get(fileURL, code); | ||
| const m = new SourceTextModule(code, { | ||
| identifier: fileURL, | ||
| context: this.context, | ||
| cachedData, | ||
| importModuleDynamically: this.executor.importModuleDynamically, | ||
| initializeImportMeta: (meta, mod) => { | ||
| meta.url = mod.identifier; | ||
| if (mod.identifier.startsWith("file:")) { | ||
| const filename = fileURLToPath(mod.identifier); | ||
| meta.filename = filename; | ||
| meta.dirname = dirname$1(filename); | ||
| } | ||
| meta.resolve = (specifier, importer) => { | ||
| return this.executor.resolve(specifier, importer != null ? importer.toString() : mod.identifier); | ||
| }; | ||
| } | ||
| }); | ||
| // the code cache of a SourceTextModule must be created before evaluation | ||
| if (!cachedData) codeCache?.store(fileURL, code, () => m.createCachedData()); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| async createWebAssemblyModule(fileUrl, getCode) { | ||
| const cached = this.moduleCache.get(fileUrl); | ||
| if (cached) return cached; | ||
| const m = this.loadWebAssemblyModule(getCode(), fileUrl); | ||
| this.moduleCache.set(fileUrl, m); | ||
| return m; | ||
| } | ||
| async createNetworkModule(fileUrl) { | ||
| // https://nodejs.org/api/esm.html#https-and-http-imports | ||
| if (fileUrl.startsWith("http:")) { | ||
| const url = new URL(fileUrl); | ||
| if (url.hostname !== "localhost" && url.hostname !== "::1" && (IPnumber(url.hostname) & IPmask(8)) !== this.#httpIp) throw new Error( | ||
| // we don't know the importer, so it's undefined (the same happens in --pool=threads) | ||
| `import of '${fileUrl}' by undefined is not supported: http can only be used to load local resources (use https instead).` | ||
| ); | ||
| } | ||
| return this.createEsModule(fileUrl, () => fetch(fileUrl).then((r) => r.text())); | ||
| } | ||
| async loadWebAssemblyModule(source, identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const wasmModule = await WebAssembly.compile(source); | ||
| const exports$1 = WebAssembly.Module.exports(wasmModule); | ||
| const imports = WebAssembly.Module.imports(wasmModule); | ||
| const moduleLookup = {}; | ||
| for (const { module } of imports) if (moduleLookup[module] === void 0) moduleLookup[module] = await this.executor.resolveModule(module, identifier); | ||
| const evaluateModule = (module) => this.evaluateModule(module); | ||
| return new SyntheticModule(exports$1.map(({ name }) => name), async function() { | ||
| const importsObject = {}; | ||
| for (const { module, name } of imports) { | ||
| if (!importsObject[module]) importsObject[module] = {}; | ||
| await evaluateModule(moduleLookup[module]); | ||
| importsObject[module][name] = moduleLookup[module].namespace[name]; | ||
| } | ||
| const wasmInstance = new WebAssembly.Instance(wasmModule, importsObject); | ||
| for (const { name } of exports$1) this.setExport(name, wasmInstance.exports[name]); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| } | ||
| cacheModule(identifier, module) { | ||
| this.moduleCache.set(identifier, module); | ||
| } | ||
| resolveCachedModule(identifier) { | ||
| return this.moduleCache.get(identifier); | ||
| } | ||
| async createDataModule(identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const match = identifier.match(dataURIRegex); | ||
| if (!match || !match.groups) throw new Error("Invalid data URI"); | ||
| const mime = match.groups.mime; | ||
| const encoding = match.groups.encoding; | ||
| if (mime === "application/wasm") { | ||
| if (!encoding) throw new Error("Missing data URI encoding"); | ||
| if (encoding !== "base64") throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| const module = this.loadWebAssemblyModule(Buffer.from(match.groups.code, "base64"), identifier); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| let code = match.groups.code; | ||
| if (!encoding || encoding === "charset=utf-8") code = decodeURIComponent(code); | ||
| else if (encoding === "base64") code = Buffer.from(code, "base64").toString(); | ||
| else throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| if (mime === "application/json") { | ||
| const module = new SyntheticModule(["default"], function() { | ||
| const obj = JSON.parse(code); | ||
| this.setExport("default", obj); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| return this.createEsModule(identifier, () => code); | ||
| } | ||
| } | ||
| function IPnumber(address) { | ||
| const ip = address.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||
| if (ip) return (+ip[1] << 24) + (+ip[2] << 16) + (+ip[3] << 8) + +ip[4]; | ||
| throw new Error(`Expected IP address, received ${address}`); | ||
| } | ||
| function IPmask(maskSize) { | ||
| return -1 << 32 - maskSize; | ||
| } | ||
| const CLIENT_ID = "/@vite/client"; | ||
| const CLIENT_FILE = pathToFileURL(CLIENT_ID).href; | ||
| class ViteExecutor { | ||
| esm; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.esm = options.esmExecutor; | ||
| } | ||
| resolve = (identifier) => { | ||
| if (identifier === CLIENT_ID) return identifier; | ||
| }; | ||
| get workerState() { | ||
| return this.options.context.__vitest_worker__; | ||
| } | ||
| async createViteModule(fileUrl) { | ||
| if (fileUrl === CLIENT_FILE || fileUrl === CLIENT_ID) return this.createViteClientModule(); | ||
| const cached = this.esm.resolveCachedModule(fileUrl); | ||
| if (cached) return cached; | ||
| return this.esm.createEsModule(fileUrl, async () => { | ||
| try { | ||
| const result = await this.options.transform(fileUrl); | ||
| if (result.code) return result.code; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url")) { | ||
| const error = new Error(`Cannot find module '${fileUrl}'`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| } | ||
| throw new Error(`[vitest] Failed to transform ${fileUrl}. Does the file exist?`); | ||
| }); | ||
| } | ||
| createViteClientModule() { | ||
| const identifier = CLIENT_ID; | ||
| const cached = this.esm.resolveCachedModule(identifier); | ||
| if (cached) return cached; | ||
| const stub = this.options.viteClientModule; | ||
| const moduleKeys = Object.keys(stub); | ||
| const module = new SyntheticModule(moduleKeys, function() { | ||
| moduleKeys.forEach((key) => { | ||
| this.setExport(key, stub[key]); | ||
| }); | ||
| }, { | ||
| context: this.options.context, | ||
| identifier | ||
| }); | ||
| this.esm.cacheModule(identifier, module); | ||
| return module; | ||
| } | ||
| canResolve = (fileUrl) => { | ||
| if (fileUrl === CLIENT_FILE) return true; | ||
| const config = this.workerState.config.deps?.web || {}; | ||
| const [modulePath] = fileUrl.split("?"); | ||
| if (config.transformCss && CSS_LANGS_RE.test(modulePath)) return true; | ||
| if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath)) return true; | ||
| if (toArray(config.transformGlobPattern).some((pattern) => pattern.test(modulePath))) return true; | ||
| return false; | ||
| }; | ||
| } | ||
| const { existsSync } = fs__default; | ||
| // always defined when we use vm pool | ||
| const nativeResolve = import.meta.resolve; | ||
| // a relative ESM specifier resolves by plain URL join — Node's resolver adds | ||
| // no information for these (it does not check existence and relative | ||
| // specifiers never consult package.json), but it re-derives the package | ||
| // scope on every uncached call, re-parsing large `exports` maps. Restricted | ||
| // to a conservative charset so anything URL-special falls back to Node. | ||
| const SIMPLE_RELATIVE_SPECIFIER_RE = /^\.{1,2}\/[\w\-./]+$/; | ||
| // TODO: improve Node.js strict mode support in #2854 | ||
| class ExternalModulesExecutor { | ||
| cjs; | ||
| esm; | ||
| vite; | ||
| context; | ||
| fs; | ||
| codeCache; | ||
| resolvers = []; | ||
| #networkSupported = null; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.codeCache = options.codeCache; | ||
| this.esm = new EsmExecutor(this, { context: this.context }); | ||
| this.cjs = new CommonjsExecutor({ | ||
| context: this.context, | ||
| importModuleDynamically: this.importModuleDynamically, | ||
| fileMap: options.fileMap, | ||
| codeCache: options.codeCache, | ||
| interopDefault: options.interopDefault | ||
| }); | ||
| this.vite = new ViteExecutor({ | ||
| esmExecutor: this.esm, | ||
| context: this.context, | ||
| transform: options.transform, | ||
| viteClientModule: options.viteClientModule | ||
| }); | ||
| this.resolvers = [this.vite.resolve]; | ||
| } | ||
| async import(identifier) { | ||
| const module = await this.createModule(identifier); | ||
| await this.esm.evaluateModule(module); | ||
| return module.namespace; | ||
| } | ||
| require(identifier) { | ||
| return this.cjs.require(identifier); | ||
| } | ||
| createRequire(identifier) { | ||
| return this.cjs.createRequire(identifier); | ||
| } | ||
| // dynamic import can be used in both ESM and CJS, so we have it in the executor | ||
| importModuleDynamically = async (specifier, referencer) => { | ||
| const module = await this.resolveModule(specifier, referencer.identifier); | ||
| return await this.esm.evaluateModule(module); | ||
| }; | ||
| resolveModule = async (specifier, referencer) => { | ||
| let identifier = this.resolve(specifier, referencer); | ||
| if (identifier instanceof Promise) identifier = await identifier; | ||
| return await this.createModule(identifier); | ||
| }; | ||
| resolve(specifier, parent) { | ||
| for (const resolver of this.resolvers) { | ||
| const id = resolver(specifier, parent); | ||
| if (id) return id; | ||
| } | ||
| if (SIMPLE_RELATIVE_SPECIFIER_RE.test(specifier) && parent.startsWith("file://")) return new URL(specifier, parent).href; | ||
| // resolution of externalized modules is stable for the lifetime of the | ||
| // worker (like fileMap/packageCache), while fresh vm contexts re-resolve | ||
| // every import edge | ||
| const cache = this.options.resolveCache; | ||
| const key = cache ? `${parent}\n${specifier}` : void 0; | ||
| if (cache) { | ||
| const cached = cache.get(key); | ||
| if (cached !== void 0) return cached; | ||
| } | ||
| // import.meta.resolve can be asynchronous in older +18 Node versions | ||
| const resolved = nativeResolve(specifier, parent); | ||
| if (cache && typeof resolved === "string") cache.set(key, resolved); | ||
| return resolved; | ||
| } | ||
| getModuleInformation(identifier) { | ||
| const cached = this.options.moduleInfoCache?.get(identifier); | ||
| if (cached) return cached; | ||
| const info = this.resolveModuleInformation(identifier); | ||
| this.options.moduleInfoCache?.set(identifier, info); | ||
| return info; | ||
| } | ||
| resolveModuleInformation(identifier) { | ||
| if (identifier.startsWith("data:")) return { | ||
| type: "data", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const { file, postfix } = splitFileAndPostfix(identifier); | ||
| const extension = extname(file); | ||
| if (extension === ".node" || isBuiltin(identifier)) return { | ||
| type: "builtin", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| if (this.isNetworkSupported && (identifier.startsWith("http:") || identifier.startsWith("https:"))) return { | ||
| type: "network", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const isFileUrl = identifier.startsWith("file://"); | ||
| const pathUrl = isFileUrl ? fileURLToPath(file) : file; | ||
| const fileUrl = isFileUrl ? identifier : `${pathToFileURL(file)}${postfix}`; | ||
| let type; | ||
| if (this.vite.canResolve(fileUrl)) type = "vite"; | ||
| else if (extension === ".mjs") type = "module"; | ||
| else if (extension === ".cjs") type = "commonjs"; | ||
| else if (extension === ".wasm") | ||
| // still experimental on NodeJS --experimental-wasm-modules | ||
| // cf. ESM_FILE_FORMAT(url) in https://nodejs.org/docs/latest-v20.x/api/esm.html#resolution-algorithm | ||
| type = "wasm"; | ||
| else type = lookupPackageScopeType(normalize(pathUrl)) === "esm" ? "module" : "commonjs"; | ||
| return { | ||
| type, | ||
| path: pathUrl, | ||
| url: fileUrl | ||
| }; | ||
| } | ||
| createModule(identifier) { | ||
| const information = this.getModuleInformation(identifier); | ||
| const { type, url, path } = information; | ||
| // create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path | ||
| // https://github.com/nodejs/node/pull/49038 | ||
| if (type === "module" || type === "commonjs" || type === "wasm") information.exists ??= existsSync(path); | ||
| if (information.exists === false) { | ||
| const error = /* @__PURE__ */ new Error(`Cannot find ${isBareImport(path) ? "package" : "module"} '${path}'`); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| switch (type) { | ||
| case "data": return this.esm.createDataModule(identifier); | ||
| case "builtin": return this.cjs.getCoreSyntheticModule(identifier); | ||
| case "vite": return this.vite.createViteModule(url); | ||
| case "wasm": return this.esm.createWebAssemblyModule(url, () => this.fs.readBuffer(path)); | ||
| case "module": return this.esm.createEsModule(url, () => this.fs.readFileAsync(path)); | ||
| case "commonjs": return this.cjs.getCjsSyntheticModule(path, identifier); | ||
| case "network": return this.esm.createNetworkModule(url); | ||
| default: return type; | ||
| } | ||
| } | ||
| get isNetworkSupported() { | ||
| if (this.#networkSupported == null) if (process.execArgv.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else if (process.env.NODE_OPTIONS?.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else this.#networkSupported = false; | ||
| return this.#networkSupported; | ||
| } | ||
| } | ||
| /** | ||
| * Worker-wide cache of V8 code cache buffers for externalized modules. | ||
| * | ||
| * vm pools create a fresh executor per test file, so every externalized | ||
| * module is compiled and evaluated again in each fresh context. The compiled | ||
| * code has no per-context state — reusing its V8 code cache skips the | ||
| * re-parse/re-compile while the evaluation still happens per context. | ||
| * | ||
| * Entries are keyed by the module identifier and guarded by the exact source | ||
| * text, so an invalidated module that produces different code simply replaces | ||
| * its entry. | ||
| */ | ||
| class CodeCache { | ||
| entries = /* @__PURE__ */ new Map(); | ||
| get(identifier, source) { | ||
| const entry = this.entries.get(identifier); | ||
| if (entry && entry.source === source) return entry.data; | ||
| } | ||
| /** | ||
| * Stores the code cache produced by `produce` unless an entry for the same | ||
| * source already exists. A `produce` failure is recorded as an empty entry, | ||
| * so it is not retried on every fresh context. | ||
| */ | ||
| store(identifier, source, produce) { | ||
| const entry = this.entries.get(identifier); | ||
| if (entry && entry.source === source) return; | ||
| let data; | ||
| try { | ||
| data = produce(); | ||
| } catch { | ||
| data = void 0; | ||
| } | ||
| this.entries.set(identifier, { | ||
| source, | ||
| data | ||
| }); | ||
| } | ||
| delete(identifier) { | ||
| this.entries.delete(identifier); | ||
| } | ||
| } | ||
| const { promises, readFileSync } = fs__default; | ||
| class FileMap { | ||
| fsCache = /* @__PURE__ */ new Map(); | ||
| fsBufferCache = /* @__PURE__ */ new Map(); | ||
| async readFileAsync(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = await promises.readFile(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readFile(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = readFileSync(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readBuffer(path) { | ||
| const cached = this.fsBufferCache.get(path); | ||
| if (cached != null) return cached; | ||
| const buffer = readFileSync(path); | ||
| this.fsBufferCache.set(path, buffer); | ||
| return buffer; | ||
| } | ||
| } | ||
| const entryFile = pathToFileURL(resolve(distDir, "workers/runVmTests.js")).href; | ||
| const fileMap = new FileMap(); | ||
| const packageCache = /* @__PURE__ */ new Map(); | ||
| const codeCache = new CodeCache(); | ||
| const resolveCache = /* @__PURE__ */ new Map(); | ||
| const moduleInfoCache = /* @__PURE__ */ new Map(); | ||
| async function runVmTests(method, state, traces) { | ||
| const { ctx, rpc } = state; | ||
| const beforeEnvironmentTime = performance.now(); | ||
| const { environment } = await loadEnvironment(ctx.environment.name, ctx.config.root, rpc, traces, true); | ||
| state.environment = environment; | ||
| // let the server transform this file's import graph while this worker is | ||
| // busy importing the environment package (jsdom takes ~0.5s per worker) — | ||
| // the server is otherwise idle during that window on a cold start. The | ||
| // transforms also land in the `fetchWarmModules` snapshot, so the worker's | ||
| // own fetches short-circuit to disk reads. Failures are ignored: the | ||
| // worker's own fetch reports them with the proper import context. | ||
| rpc.prewarmModuleGraph(environment.viteEnvironment || environment.name, ctx.files.map((file) => file.filepath)).catch(() => {}); | ||
| if (!environment.setupVM) { | ||
| const envName = ctx.environment.name; | ||
| const packageId = envName[0] === "." ? envName : `vitest-environment-${envName}`; | ||
| throw new TypeError(`Environment "${ctx.environment.name}" is not a valid environment. Path "${packageId}" doesn't support vm environment because it doesn't provide "setupVM" method.`); | ||
| } | ||
| const vm = await traces.$("vitest.runtime.environment.setup", { attributes: { | ||
| "vitest.environment": environment.name, | ||
| "vitest.environment.vite_environment": environment.viteEnvironment || environment.name | ||
| } }, () => environment.setupVM(ctx.environment.options || ctx.config.environmentOptions || {})); | ||
| state.durations.environment = performance.now() - beforeEnvironmentTime; | ||
| process.env.VITEST_VM_POOL = "1"; | ||
| if (!vm.getVmContext) throw new TypeError(`Environment ${environment.name} doesn't provide "getVmContext" method. It should return a context created by "vm.createContext" method.`); | ||
| const context = vm.getVmContext(); | ||
| if (!isContext(context)) throw new TypeError(`Environment ${environment.name} doesn't provide a valid context. It should be created by "vm.createContext" method.`); | ||
| provideWorkerState(context, state); | ||
| // this is unfortunately needed for our own dependencies | ||
| // we need to find a way to not rely on this by default | ||
| // because browser doesn't provide these globals | ||
| context.process = process; | ||
| context.global = context; | ||
| context.console = state.config.disableConsoleIntercept ? console : createCustomConsole(state); | ||
| // TODO: don't hardcode setImmediate in fake timers defaults | ||
| context.setImmediate = setImmediate; | ||
| context.clearImmediate = clearImmediate; | ||
| const stubs = getDefaultRequestStubs(context); | ||
| const externalModulesExecutor = new ExternalModulesExecutor({ | ||
| context, | ||
| fileMap, | ||
| codeCache, | ||
| resolveCache, | ||
| moduleInfoCache, | ||
| packageCache, | ||
| transform: rpc.transform, | ||
| viteClientModule: stubs["/@vite/client"] | ||
| }); | ||
| process.exit = (code = process.exitCode || 0) => { | ||
| throw new Error(`process.exit unexpectedly called with "${code}"`); | ||
| }; | ||
| listenForErrors(() => state); | ||
| const moduleRunner = startVitestModuleRunner({ | ||
| context, | ||
| evaluatedModules: state.evaluatedModules, | ||
| state, | ||
| externalModulesExecutor, | ||
| createImportMeta: createNodeImportMeta, | ||
| traces | ||
| }); | ||
| emitModuleRunner(moduleRunner); | ||
| Object.defineProperty(context, VITEST_VM_CONTEXT_SYMBOL, { | ||
| value: { | ||
| context, | ||
| externalModulesExecutor | ||
| }, | ||
| configurable: true, | ||
| enumerable: false, | ||
| writable: false | ||
| }); | ||
| context.__vitest_mocker__ = moduleRunner.mocker; | ||
| setupEnv(ctx.config.env, state.metaEnv); | ||
| if (ctx.config.serializedDefines) try { | ||
| runInContext(ctx.config.serializedDefines, context, { filename: "virtual:load-defines.js" }); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom "defines": ${error.message}`); | ||
| } | ||
| await moduleRunner.mocker.initializeSpyModule(); | ||
| const { run } = await moduleRunner.import(entryFile); | ||
| try { | ||
| await run(method, ctx.files, ctx.config, moduleRunner, traces); | ||
| } finally { | ||
| await traces.$("vitest.runtime.environment.teardown", () => vm.teardown?.()); | ||
| } | ||
| } | ||
| function setupVmWorker(context) { | ||
| if (context.config.experimental.viteModuleRunner === false) throw new Error(`Pool "${context.pool}" cannot run with "experimental.viteModuleRunner: false". Please, use "threads" or "forks" instead.`); | ||
| } | ||
| export { runVmTests as r, setupVmWorker as s }; |
| import { EvaluatedModules } from 'vite/module-runner'; | ||
| import { be as FileSpecification, x as SerializedConfig, z as Task, B as CancelReason } from './config.d.DsC1jkby.js'; | ||
| import { a as RuntimeRPC, R as RunnerRPC, G as GetterTracker } from './rpc.d.BeasqWpO.js'; | ||
| import { E as Environment } from './environment.d.4-rzQgpt.js'; | ||
| //#region src/messages.d.ts | ||
| declare const TYPE_REQUEST: "q"; | ||
| interface RpcRequest { | ||
| /** | ||
| * Type | ||
| */ | ||
| t: typeof TYPE_REQUEST; | ||
| /** | ||
| * ID | ||
| */ | ||
| i?: string; | ||
| /** | ||
| * Method | ||
| */ | ||
| m: string; | ||
| /** | ||
| * Arguments | ||
| */ | ||
| a: any[]; | ||
| /** | ||
| * Optional | ||
| */ | ||
| o?: boolean; | ||
| } | ||
| //#endregion | ||
| //#region src/utils.d.ts | ||
| type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never; | ||
| type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never; | ||
| type Thenable<T> = T | PromiseLike<T>; | ||
| //#endregion | ||
| //#region src/main.d.ts | ||
| type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>; | ||
| type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>; | ||
| interface ChannelOptions { | ||
| /** | ||
| * Function to post raw message | ||
| */ | ||
| post: (data: any, ...extras: any[]) => Thenable<any>; | ||
| /** | ||
| * Listener to receive raw message | ||
| */ | ||
| on: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>; | ||
| /** | ||
| * Clear the listener when `$close` is called | ||
| */ | ||
| off?: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>; | ||
| /** | ||
| * Custom function to serialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| serialize?: (data: any) => any; | ||
| /** | ||
| * Custom function to deserialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| deserialize?: (data: any) => any; | ||
| /** | ||
| * Call the methods with the RPC context or the original functions object | ||
| */ | ||
| bind?: 'rpc' | 'functions'; | ||
| /** | ||
| * Custom meta data to attached to the RPC instance's `$meta` property | ||
| */ | ||
| meta?: any; | ||
| } | ||
| interface EventOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> { | ||
| /** | ||
| * Names of remote functions that do not need response. | ||
| */ | ||
| eventNames?: (keyof RemoteFunctions)[]; | ||
| /** | ||
| * Maximum timeout for waiting for response, in milliseconds. | ||
| * | ||
| * @default 60_000 | ||
| */ | ||
| timeout?: number; | ||
| /** | ||
| * Whether to proxy the remote functions. | ||
| * | ||
| * When `proxify` is false, calling the remote function | ||
| * with `rpc.$call('method', ...args)` instead of `rpc.method(...args)` | ||
| * explicitly is required. | ||
| * | ||
| * @default true | ||
| */ | ||
| proxify?: Proxify; | ||
| /** | ||
| * Custom resolver to resolve function to be called | ||
| * | ||
| * For advanced use cases only | ||
| */ | ||
| resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>>; | ||
| /** | ||
| * Hook triggered before an event is sent to the remote | ||
| * | ||
| * @param req - Request parameters | ||
| * @param next - Function to continue the request | ||
| * @param resolve - Function to resolve the response directly | ||
| */ | ||
| onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, req: RpcRequest, next: (req?: RpcRequest) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>; | ||
| /** | ||
| * Custom error handler for errors occurred in local functions being called | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred during serialization or messsaging | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName?: string, args?: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for timeouts | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, functionName: string, args: any[]) => boolean | void; | ||
| } | ||
| type BirpcOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = EventOptions<RemoteFunctions, LocalFunctions, Proxify> & ChannelOptions; | ||
| type BirpcFn<T> = PromisifyFn<T> & { | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| }; | ||
| interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, unknown>> { | ||
| /** | ||
| * Raw functions object | ||
| */ | ||
| $functions: LocalFunctions; | ||
| /** | ||
| * Whether the RPC is closed | ||
| */ | ||
| readonly $closed: boolean; | ||
| /** | ||
| * Custom meta data attached to the RPC instance | ||
| */ | ||
| readonly $meta: any; | ||
| /** | ||
| * Close the RPC connection | ||
| */ | ||
| $close: (error?: Error) => void; | ||
| /** | ||
| * Reject pending calls | ||
| */ | ||
| $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[]; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function with the raw options. | ||
| */ | ||
| $callRaw: (options: { | ||
| method: string; | ||
| args: unknown[]; | ||
| event?: boolean; | ||
| optional?: boolean; | ||
| }) => Promise<Awaited<ReturnType<any>>[]>; | ||
| } | ||
| type ProxifiedRemoteFunctions<RemoteFunctions extends object = Record<string, unknown>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> }; | ||
| type BirpcReturn<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = Proxify extends true ? ProxifiedRemoteFunctions<RemoteFunctions> & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions> : BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>; | ||
| type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>; | ||
| interface PromiseEntry { | ||
| resolve: (arg: any) => void; | ||
| reject: (error: any) => void; | ||
| method: string; | ||
| timeoutId?: ReturnType<typeof setTimeout>; | ||
| } | ||
| declare const setTimeout: typeof globalThis.setTimeout; | ||
| type WorkerRPC = BirpcReturn<RuntimeRPC, RunnerRPC>; | ||
| interface ContextTestEnvironment { | ||
| name: string; | ||
| options: Record<string, any> | null; | ||
| } | ||
| interface WorkerTestEnvironment { | ||
| name: string; | ||
| options: Record<string, any> | null; | ||
| } | ||
| type TestExecutionMethod = "run" | "collect"; | ||
| interface WorkerExecuteContext { | ||
| files: FileSpecification[]; | ||
| providedContext: Record<string, any>; | ||
| invalidates?: string[]; | ||
| environment: ContextTestEnvironment; | ||
| /** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */ | ||
| workerId: number; | ||
| } | ||
| interface MetaEnv { | ||
| [key: string]: any; | ||
| BASE_URL: string; | ||
| MODE: string; | ||
| DEV: boolean; | ||
| PROD: boolean; | ||
| SSR: boolean; | ||
| } | ||
| interface ContextRPC { | ||
| pool: string; | ||
| config: SerializedConfig; | ||
| projectName: string; | ||
| environment: WorkerTestEnvironment; | ||
| rpc: WorkerRPC; | ||
| metaEnv: MetaEnv; | ||
| files: FileSpecification[]; | ||
| providedContext: Record<string, any>; | ||
| invalidates?: string[]; | ||
| /** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */ | ||
| workerId: number; | ||
| concurrencyId: number; | ||
| } | ||
| interface WorkerSetupContext { | ||
| environment: WorkerTestEnvironment; | ||
| pool: string; | ||
| config: SerializedConfig; | ||
| projectName: string; | ||
| rpc: WorkerRPC; | ||
| metaEnv: MetaEnv; | ||
| } | ||
| interface WorkerGlobalState { | ||
| ctx: ContextRPC; | ||
| config: SerializedConfig; | ||
| rpc: WorkerRPC; | ||
| current?: Task; | ||
| filepath?: string; | ||
| metaEnv: MetaEnv; | ||
| environment: Environment; | ||
| evaluatedModules: EvaluatedModules; | ||
| resolvingModules: Set<string>; | ||
| moduleExecutionInfo: Map<string, any>; | ||
| getterTracker?: GetterTracker; | ||
| onCancel: (listener: (reason: CancelReason) => unknown) => void; | ||
| onCleanup: (listener: () => unknown) => void; | ||
| providedContext: Record<string, any>; | ||
| durations: { | ||
| environment: number; | ||
| prepare: number; | ||
| }; | ||
| onFilterStackTrace?: (trace: string) => string; | ||
| } | ||
| export type { BirpcReturn as B, ContextRPC as C, TestExecutionMethod as T, WorkerGlobalState as W, ContextTestEnvironment as a, WorkerExecuteContext as b, WorkerTestEnvironment as c, WorkerSetupContext as d, BirpcOptions as e }; |
+27
-14
@@ -1,16 +0,26 @@ | ||
| import { a4 as SerializedCoverageConfig, aH as FileSpecification, V as VitestRunner, F as File, n as SerializedConfig } from './chunks/config.d.CKWK3nld.js'; | ||
| import { R as RuntimeCoverageModuleLoader } from './chunks/coverage.d.CCNrKR65.js'; | ||
| import { SerializedDiffOptions } from '@vitest/utils/diff'; | ||
| import * as _vitest_spy from '@vitest/spy'; | ||
| export { _vitest_spy as SpyModule }; | ||
| export { ParsedStack, StringifyOptions } from '@vitest/utils'; | ||
| export { format, inspect, stringify } from '@vitest/utils/display'; | ||
| export { processError } from '@vitest/utils/error'; | ||
| export { getType } from '@vitest/utils/helpers'; | ||
| export { DecodedMap, getOriginalPosition } from '@vitest/utils/source-map'; | ||
| export { getSafeTimers, setSafeTimers } from '@vitest/utils/timers'; | ||
| import '@vitest/pretty-format'; | ||
| import 'tinyrainbow'; | ||
| import { az as SerializedCoverageConfig, be as FileSpecification, V as VitestRunner, F as File, x as SerializedConfig, bf as SerializedDiffOptions, a8 as DiffOptions, aU as TestError } from './chunks/config.d.DsC1jkby.js'; | ||
| export { au as ParsedStack, bg as SpyModule, bh as StringifyOptions, bi as format, bj as inspect, bk as stringify } from './chunks/config.d.DsC1jkby.js'; | ||
| import { R as RuntimeCoverageModuleLoader } from './chunks/coverage.d.ByaAMV4A.js'; | ||
| export { D as DecodedMap, g as getOriginalPosition } from './chunks/coverage.d.ByaAMV4A.js'; | ||
| import 'vitest/optional-runtime-types.js'; | ||
| import 'tinybench'; | ||
| declare function getType(value: unknown): string; | ||
| interface SafeTimers { | ||
| nextTick?: (cb: () => void) => void; | ||
| setImmediate?: { | ||
| <TArgs extends any[]>(callback: (...args: TArgs) => void, ...args: TArgs): any; | ||
| __promisify__: <T = void>(value?: T, options?: any) => Promise<T>; | ||
| }; | ||
| clearImmediate?: (immediateId: any) => void; | ||
| setTimeout: typeof setTimeout; | ||
| setInterval: typeof setInterval; | ||
| clearInterval: typeof clearInterval; | ||
| clearTimeout: typeof clearTimeout; | ||
| queueMicrotask: typeof queueMicrotask; | ||
| } | ||
| declare function getSafeTimers(): SafeTimers; | ||
| declare function setSafeTimers(): void; | ||
| declare function startCoverageInsideWorker(options: SerializedCoverageConfig, loader: RuntimeCoverageModuleLoader, runtimeOptions: { | ||
@@ -32,5 +42,8 @@ isolate: boolean; | ||
| declare function setupCommonEnv(config: SerializedConfig): Promise<void>; | ||
| declare function setupEnv(env: Record<string, any>, metaEnv: Record<string, any>): void; | ||
| declare function loadDiffConfig(config: SerializedConfig, moduleRunner: PublicModuleRunner): Promise<SerializedDiffOptions | undefined>; | ||
| declare function loadSnapshotSerializers(config: SerializedConfig, moduleRunner: PublicModuleRunner): Promise<void>; | ||
| declare function processError(_err: any, diffOptions?: DiffOptions, seen?: WeakSet<WeakKey>): TestError; | ||
| interface FsOptions { | ||
@@ -49,3 +62,3 @@ encoding?: BufferEncoding; | ||
| export { FileSpecification, publicCollect as collectTests, loadDiffConfig, loadSnapshotSerializers, setupCommonEnv, startCoverageInsideWorker, startTests, stopCoverageInsideWorker, takeCoverageInsideWorker }; | ||
| export { FileSpecification, publicCollect as collectTests, getSafeTimers, getType, loadDiffConfig, loadSnapshotSerializers, processError, setSafeTimers, setupCommonEnv, setupEnv, startCoverageInsideWorker, startTests, stopCoverageInsideWorker, takeCoverageInsideWorker }; | ||
| export type { BrowserCommands, CDPSession, FsOptions }; |
+11
-14
@@ -1,16 +0,13 @@ | ||
| export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/setup-common.ZNdeu5wa.js'; | ||
| export { p as collectTests, s as startTests } from './chunks/artifact.BNnEI1sJ.js'; | ||
| import * as spyModule from '@vitest/spy'; | ||
| export { spyModule as SpyModule }; | ||
| export { format, inspect, stringify } from '@vitest/utils/display'; | ||
| export { processError } from '@vitest/utils/error'; | ||
| export { getType } from '@vitest/utils/helpers'; | ||
| export { DecodedMap, getOriginalPosition } from '@vitest/utils/source-map'; | ||
| export { getSafeTimers, setSafeTimers } from '@vitest/utils/timers'; | ||
| import './chunks/coverage.CTzCuANN.js'; | ||
| import './chunks/utils.DYj33du9.js'; | ||
| import './chunks/plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| export { s as startCoverageInsideWorker, a as stopCoverageInsideWorker, t as takeCoverageInsideWorker } from './chunks/coverage.BfSEMtie.js'; | ||
| export { p as collectTests, a as processError, s as startTests } from './chunks/artifact.DC5WoEgy.js'; | ||
| export { l as loadDiffConfig, a as loadSnapshotSerializers, s as setupCommonEnv, b as setupEnv } from './chunks/setup-common.vxjAyUtK.js'; | ||
| export { s as SpyModule } from './chunks/spy.B8mHA9qu.js'; | ||
| export { f as format, i as inspect, s as stringify } from './chunks/display.CYwyMF4S.js'; | ||
| export { g as getType } from './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| export { D as DecodedMap, g as getOriginalPosition, a as getSafeTimers, s as setSafeTimers } from './chunks/source-map.DZdIqpIJ.js'; | ||
| import './chunks/coverage.BVb1JqW7.js'; | ||
| import './chunks/index.DzTmMrSM.js'; | ||
| import './chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import './task-utils.js'; | ||
| import 'pathe'; | ||
| import './chunks/plugins.CsoX-42X.js'; | ||
@@ -17,0 +14,0 @@ /** |
+4
-5
@@ -1,7 +0,6 @@ | ||
| import { c as createCLI } from './chunks/cac.DKrA6qEB.js'; | ||
| import '@vitest/utils/helpers'; | ||
| import { c as createCLI } from './chunks/cac.B41kXwyU.js'; | ||
| import './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import 'events'; | ||
| import 'pathe'; | ||
| import 'tinyrainbow'; | ||
| import './chunks/env.BKKtU2WC.js'; | ||
| import './chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import './chunks/env.DzFJjrmK.js'; | ||
| import 'std-env'; | ||
@@ -8,0 +7,0 @@ import './chunks/constants.-juJ8b_4.js'; |
+1
-0
@@ -54,2 +54,3 @@ 'use strict'; | ||
| globals: false, | ||
| injectCjsGlobals: true, | ||
| environment: "node", | ||
@@ -56,0 +57,0 @@ clearMocks: true, |
+19
-17
| import { HookHandler, UserConfig, ConfigEnv } from 'vite'; | ||
| export { ConfigEnv, Plugin, UserConfig as ViteUserConfig, mergeConfig } from 'vite'; | ||
| import { a1 as InlineConfig, aS as VitestPluginContext, I as CoverageOptions, aX as FieldsWithDefaultValues, aO as UserWorkspaceConfig, aY as UserProjectConfigFn, aZ as UserProjectConfigExport } from './chunks/plugin.d.Bpge8Jye.js'; | ||
| export { a_ as TestProjectConfiguration, a$ as TestProjectInlineConfiguration, U as TestUserConfig, aT as WatcherTriggerPattern } from './chunks/plugin.d.Bpge8Jye.js'; | ||
| import { C as Config } from './chunks/config.d.CKWK3nld.js'; | ||
| export { aq as TestTagDefinition } from './chunks/config.d.CKWK3nld.js'; | ||
| import '@vitest/utils'; | ||
| import { a3 as InlineConfig, R as ResolvedConfig, aU as VitestPluginContext, K as CoverageOptions, a_ as FieldsWithDefaultValues, aQ as UserWorkspaceConfig, a$ as UserProjectConfigFn, b0 as UserProjectConfigExport } from './chunks/plugin.d.BOjbmxWW.js'; | ||
| export { b1 as TestProjectConfiguration, b2 as TestProjectInlineConfiguration, U as TestUserConfig, aV as WatcherTriggerPattern } from './chunks/plugin.d.BOjbmxWW.js'; | ||
| import { C as Config } from './chunks/config.d.DsC1jkby.js'; | ||
| export { aX as TestTagDefinition } from './chunks/config.d.DsC1jkby.js'; | ||
| import 'node:stream'; | ||
| import './chunks/browser.d.DoM6vBOs.js'; | ||
| import './chunks/rpc.d.C6-dGZ2f.js'; | ||
| import './chunks/browser.d.BFOby8YL.js'; | ||
| import './chunks/rpc.d.BeasqWpO.js'; | ||
| import 'vite/module-runner'; | ||
| import './chunks/worker.d.JES7ffPK.js'; | ||
| import './chunks/environment.d.CrsxCzP1.js'; | ||
| import 'node:fs/promises'; | ||
| import '@vitest/pretty-format'; | ||
| import '@vitest/utils/diff'; | ||
| import './chunks/worker.d.s_RdeZtI.js'; | ||
| import './chunks/environment.d.4-rzQgpt.js'; | ||
| import 'chai'; | ||
| import 'vitest/optional-types.js'; | ||
| import '@vitest/mocker'; | ||
| import '@vitest/utils/source-map'; | ||
| import './chunks/coverage.d.ByaAMV4A.js'; | ||
| import 'vitest/browser'; | ||
| import './chunks/coverage.d.CCNrKR65.js'; | ||
| import 'node:console'; | ||
| import 'node:fs/promises'; | ||
| import 'node:fs'; | ||
| import '@vitest/spy'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/display'; | ||
| import 'vitest/optional-runtime-types.js'; | ||
| import 'tinybench'; | ||
| type VitestInlineConfig = InlineConfig; | ||
| type VitestResolvedConfig = ResolvedConfig; | ||
| declare module "vite" { | ||
@@ -38,2 +33,8 @@ interface UserConfig { | ||
| } | ||
| interface ResolvedConfig { | ||
| /** | ||
| * Options for Vitest | ||
| */ | ||
| test: VitestResolvedConfig; | ||
| } | ||
| interface Plugin<A = any> { | ||
@@ -54,2 +55,3 @@ configureVitest?: HookHandler<(context: VitestPluginContext) => void>; | ||
| globals: boolean; | ||
| injectCjsGlobals: boolean; | ||
| environment: "node"; | ||
@@ -56,0 +58,0 @@ clearMocks: boolean; |
+2
-2
@@ -1,6 +0,6 @@ | ||
| export { c as configDefaults, a as coverageConfigDefaults, d as defaultExclude, b as defaultInclude } from './chunks/defaults.B_pFOTYy.js'; | ||
| export { c as configDefaults, a as coverageConfigDefaults, d as defaultExclude, b as defaultInclude } from './chunks/defaults.BJUmAuaO.js'; | ||
| export { mergeConfig } from 'vite'; | ||
| export { d as defaultBrowserPort } from './chunks/constants.-juJ8b_4.js'; | ||
| import 'node:os'; | ||
| import './chunks/env.BKKtU2WC.js'; | ||
| import './chunks/env.DzFJjrmK.js'; | ||
| import 'std-env'; | ||
@@ -7,0 +7,0 @@ |
+14
-29
@@ -1,28 +0,19 @@ | ||
| import { F as File, T as TestAnnotation, a as TestArtifact, b as TaskResultPack, c as TaskEventPack, U as UserConsoleLog, S as SerializedRootConfig, L as LabelColor, M as ModuleGraphData, d as Test, e as TaskPopulated, E as ExpectStatic, P as ProvidedContext, f as MatcherState, g as SyncExpectationResult, A as AsyncExpectationResult, D as DomainSnapshotAdapter, h as ExpectationResult, C as Config, R as RuntimeOptions, i as TestAPI, j as SuiteCollector, k as SuiteAPI, l as Suite, m as SuiteHooks, V as VitestRunner, n as SerializedConfig, o as VitestRunnerImportSource, p as Task, q as CancelReason, r as TestTryOptions, s as TestContext, I as ImportDuration, t as createChainable } from './chunks/config.d.CKWK3nld.js'; | ||
| export { u as AfterSuiteRunMeta, v as Assertion, w as AsymmetricMatchersContaining, B as BaselineData, x as Bench, y as BenchFnOptions, z as BenchFromSource, G as BenchRegistration, H as BenchResult, J as BenchStorage, K as BrowserTraceArtifact, N as DeeplyAllowMatchers, O as DomainMatchResult, Q as FailureScreenshotArtifact, W as JestAssertion, X as Matcher, Y as Matchers, Z as MatchersObject, _ as OnTestFailedHandler, $ as OnTestFinishedHandler, a0 as RunMode, a1 as RunnerTaskBase, a2 as RunnerTaskResult, a3 as RuntimeConfig, a4 as SerializedCoverageConfig, a5 as SnapshotData, a6 as SnapshotMatchOptions, a7 as SnapshotResult, a8 as SnapshotSerializer, a9 as SnapshotStateOptions, aa as SnapshotSummary, ab as SnapshotUpdateState, ac as SuiteFactory, ad as SuiteOptions, ae as TaskCustomOptions, af as TaskMeta, ag as TaskState, ah as TestAnnotationArtifact, ai as TestArtifactBase, aj as TestArtifactLocation, ak as TestArtifactRegistry, al as TestAttachment, am as TestBenchmark, an as TestBenchmarkTask, ao as TestFunction, ap as TestOptions, aq as TestTagDefinition, ar as TestTags, as as UncheckedSnapshot, at as VisualRegressionArtifact, au as afterAll, av as afterEach, aw as aroundAll, ax as aroundEach, ay as beforeAll, az as beforeEach, aA as onTestFailed, aB as onTestFinished } from './chunks/config.d.CKWK3nld.js'; | ||
| import { M as ModuleDefinitionDurationsDiagnostic, U as UntrackedModuleDefinitionDiagnostic, S as SerializedTestSpecification, a as ModuleDefinitionDiagnostic, b as ModuleDefinitionLocation, c as SourceModuleDiagnostic, d as SourceModuleLocations } from './chunks/browser.d.DoM6vBOs.js'; | ||
| export { B as BrowserTesterOptions } from './chunks/browser.d.DoM6vBOs.js'; | ||
| import { c as createFileTask } from './chunks/task-utils.d.mMDXJF_I.js'; | ||
| import { Awaitable } from '@vitest/utils'; | ||
| export { ParsedStack, SerializedError, TestError } from '@vitest/utils'; | ||
| import { B as BirpcReturn } from './chunks/worker.d.JES7ffPK.js'; | ||
| export { C as ContextRPC, a as ContextTestEnvironment, T as TestExecutionMethod, W as WorkerGlobalState } from './chunks/worker.d.JES7ffPK.js'; | ||
| import { Procedure, Mock, spyOn, fn, MaybeMockedDeep, MaybeMocked, MaybePartiallyMocked, MaybePartiallyMockedDeep, MockInstance } from '@vitest/spy'; | ||
| export { Mock, MockContext, MockInstance, MockResult, MockResultIncomplete, MockResultReturn, MockResultThrow, MockSettledResult, MockSettledResultFulfilled, MockSettledResultIncomplete, MockSettledResultRejected, Mocked, MockedClass, MockedFunction, MockedObject } from '@vitest/spy'; | ||
| import { F as File, A as Awaitable, T as TestAnnotation, a as TestArtifact, b as TaskResultPack, c as TaskEventPack, U as UserConsoleLog, S as SerializedRootConfig, L as LabelColor, M as ModuleGraphData, d as Test, e as TaskPopulated, E as ExpectStatic, P as ProvidedContext, f as MatcherState, g as SyncExpectationResult, h as AsyncExpectationResult, D as DomainSnapshotAdapter, i as ExpectationResult, j as Procedure, k as Mock, C as Config, s as spyOn, l as fn, m as MaybeMockedDeep, n as MaybeMocked, o as MaybePartiallyMocked, p as MaybePartiallyMockedDeep, q as MockInstance, R as RuntimeOptions, r as TestAPI, t as SuiteCollector, u as SuiteAPI, v as Suite, w as SuiteHooks, V as VitestRunner, x as SerializedConfig, y as VitestRunnerImportSource, z as Task, B as CancelReason, G as TestTryOptions, H as TestContext, I as ImportDuration, J as createChainable } from './chunks/config.d.DsC1jkby.js'; | ||
| export { K as AfterSuiteRunMeta, N as Assertion, O as AsymmetricMatchersContaining, Q as BaselineData, W as Bench, X as BenchFn, Y as BenchFnOptions, Z as BenchFromSource, _ as BenchOptions, $ as BenchRegistration, a0 as BenchRegistrationInput, a1 as BenchResult, a2 as BenchRunOptions, a3 as BenchStorage, a4 as BenchmarkGroup, a5 as BenchmarkProvider, a6 as BrowserTraceArtifact, a7 as DeeplyAllowMatchers, a8 as DiffOptions, a9 as DomainMatchResult, aa as FailureScreenshotArtifact, ab as JestAssertion, ac as Matcher, ad as Matchers, ae as MatchersObject, af as MockContext, ag as MockResult, ah as MockResultIncomplete, ai as MockResultReturn, aj as MockResultThrow, ak as MockSettledResult, al as MockSettledResultFulfilled, am as MockSettledResultIncomplete, an as MockSettledResultRejected, ao as Mocked, ap as MockedClass, aq as MockedFunction, ar as MockedObject, as as OnTestFailedHandler, at as OnTestFinishedHandler, au as ParsedStack, av as RunMode, aw as RunnerTaskBase, ax as RunnerTaskResult, ay as RuntimeConfig, az as SerializedCoverageConfig, aA as SerializedError, aB as SnapshotData, aC as SnapshotMatchOptions, aD as SnapshotResult, aE as SnapshotSerializer, aF as SnapshotStateOptions, aG as SnapshotSummary, aH as SnapshotUpdateState, aI as SuiteFactory, aJ as SuiteOptions, aK as TaskCustomOptions, aL as TaskMeta, aM as TaskState, aN as TestAnnotationArtifact, aO as TestArtifactBase, aP as TestArtifactLocation, aQ as TestArtifactRegistry, aR as TestAttachment, aS as TestBenchmark, aT as TestBenchmarkTask, aU as TestError, aV as TestFunction, aW as TestOptions, aX as TestTagDefinition, aY as TestTags, aZ as UncheckedSnapshot, a_ as VisualRegressionArtifact, a$ as afterAll, b0 as afterEach, b1 as aroundAll, b2 as aroundEach, b3 as beforeAll, b4 as beforeEach, b5 as onTestFailed, b6 as onTestFinished } from './chunks/config.d.DsC1jkby.js'; | ||
| import { M as ModuleDefinitionDurationsDiagnostic, U as UntrackedModuleDefinitionDiagnostic, S as SerializedTestSpecification, a as ModuleDefinitionDiagnostic, b as ModuleDefinitionLocation, c as SourceModuleDiagnostic, d as SourceModuleLocations } from './chunks/browser.d.BFOby8YL.js'; | ||
| export { B as BrowserTesterOptions } from './chunks/browser.d.BFOby8YL.js'; | ||
| import { c as createFileTask } from './chunks/task-utils.d.BKHiHxSN.js'; | ||
| import { B as BirpcReturn } from './chunks/worker.d.s_RdeZtI.js'; | ||
| export { C as ContextRPC, a as ContextTestEnvironment, T as TestExecutionMethod, W as WorkerGlobalState } from './chunks/worker.d.s_RdeZtI.js'; | ||
| import { Disposable } from 'vitest/optional-runtime-types.js'; | ||
| import { ModuleMockFactoryWithHelper, ModuleMockOptions } from '@vitest/mocker'; | ||
| export { V as EvaluatedModules } from './chunks/evaluatedModules.d.BxJ5omdx.js'; | ||
| import { Bench, Task as Task$1 } from 'tinybench'; | ||
| import { T as Traces } from './chunks/rpc.d.BeasqWpO.js'; | ||
| export { R as RunnerRPC, a as RuntimeRPC } from './chunks/rpc.d.BeasqWpO.js'; | ||
| export { ExpectTypeOf, expectTypeOf } from 'expect-type'; | ||
| export { BenchOptions as BenchCompareOptions } from 'tinybench'; | ||
| import { T as Traces } from './chunks/rpc.d.C6-dGZ2f.js'; | ||
| export { R as RunnerRPC, a as RuntimeRPC } from './chunks/rpc.d.C6-dGZ2f.js'; | ||
| export { ExpectTypeOf, expectTypeOf } from 'expect-type'; | ||
| export { DiffOptions } from '@vitest/utils/diff'; | ||
| import * as chai from 'chai'; | ||
| export { chai }; | ||
| import '@vitest/pretty-format'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/display'; | ||
| import 'vite/module-runner'; | ||
| import './chunks/environment.d.CrsxCzP1.js'; | ||
| import './chunks/environment.d.4-rzQgpt.js'; | ||
@@ -67,3 +58,3 @@ interface SourceMap { | ||
| }[]; | ||
| getModuleGraph: (projectName: string, id: string) => Promise<ModuleGraphData>; | ||
| getModuleGraph: (projectName: string, id: string, viteEnvironment?: string) => Promise<ModuleGraphData>; | ||
| getTransformResult: (projectName: string, id: string, testFileId: string) => Promise<TransformResultWithSource | undefined>; | ||
@@ -813,3 +804,3 @@ getExternalResult: (id: string, testFileId: string) => Promise<ExternalResult | undefined>; | ||
| */ | ||
| stubEnv: <T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => VitestUtils; | ||
| stubEnv: <T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean | undefined : string | undefined) => VitestUtils; | ||
| /** | ||
@@ -1058,8 +1049,2 @@ * Reset the value to original value that was available before first `vi.stubGlobal` was called. | ||
| static createFileTask: typeof createFileTask; | ||
| /** | ||
| * @experimental | ||
| * A function that runs tinybench tasks. | ||
| * Can be overriden to run tasks in a special environment. | ||
| */ | ||
| static runBenchmarks(tinybench: Bench): Promise<Task$1[]>; | ||
| } | ||
@@ -1084,3 +1069,3 @@ | ||
| export { AsyncExpectationResult as AsyncMatcherResult, CancelReason, DomainSnapshotAdapter, ExpectStatic, Experimental, ImportDuration, LabelColor, ExpectationResult as MatcherResult, MatcherState, ModuleGraphData, ProvidedContext, Task as RunnerTask, TaskEventPack as RunnerTaskEventPack, TaskResultPack as RunnerTaskResultPack, Test as RunnerTestCase, File as RunnerTestFile, Suite as RunnerTestSuite, SerializedConfig, SerializedRootConfig, SerializedTestSpecification, Snapshots, SuiteAPI, SuiteCollector, SyncExpectationResult as SyncMatcherResult, TestAPI, TestAnnotation, TestArtifact, TestContext, TestRunner, TestTryOptions, UserConsoleLog, VitestRunner as VitestTestRunner, assert, assertType, createExpect, describe, globalExpect as expect, inject, it, recordArtifact, should, suite, test, vi, vitest }; | ||
| export { AsyncExpectationResult as AsyncMatcherResult, CancelReason, DomainSnapshotAdapter, ExpectStatic, Experimental, ImportDuration, LabelColor, ExpectationResult as MatcherResult, MatcherState, Mock, MockInstance, ModuleGraphData, ProvidedContext, Task as RunnerTask, TaskEventPack as RunnerTaskEventPack, TaskResultPack as RunnerTaskResultPack, Test as RunnerTestCase, File as RunnerTestFile, Suite as RunnerTestSuite, SerializedConfig, SerializedRootConfig, SerializedTestSpecification, Snapshots, SuiteAPI, SuiteCollector, SyncExpectationResult as SyncMatcherResult, TestAPI, TestAnnotation, TestArtifact, TestContext, TestRunner, TestTryOptions, UserConsoleLog, VitestRunner as VitestTestRunner, assert, assertType, createExpect, describe, globalExpect as expect, inject, it, recordArtifact, should, suite, test, vi, vitest }; | ||
| export type { AssertType, BrowserUI, ExternalResult, TestRunnerConfig, TransformResultWithSource, VitestUtils, WebSocketEvents, WebSocketHandlers, WebSocketRPC }; |
+11
-16
@@ -1,4 +0,4 @@ | ||
| export { S as Snapshots, T as TestRunner, a as assert, b as assertType, c as createExpect, g as expect, d as inject, s as should, v as vi, e as vitest } from './chunks/index.D6NDM5O1.js'; | ||
| export { V as EvaluatedModules } from './chunks/rpc.DZEh5xnQ.js'; | ||
| export { f as afterAll, h as afterEach, i as aroundAll, j as aroundEach, k as beforeAll, l as beforeEach, n as describe, o as it, q as onTestFailed, r as onTestFinished, t as recordArtifact, u as suite, v as test } from './chunks/artifact.BNnEI1sJ.js'; | ||
| export { S as Snapshots, T as TestRunner, a as assert, b as assertType, c as createExpect, g as expect, d as inject, s as should, v as vi, e as vitest } from './chunks/index.CLtI1k_4.js'; | ||
| export { V as EvaluatedModules } from './chunks/rpc.iNjF664v.js'; | ||
| export { j as afterAll, k as afterEach, l as aroundAll, n as aroundEach, o as beforeAll, q as beforeEach, r as describe, t as it, u as onTestFailed, v as onTestFinished, w as recordArtifact, x as suite, y as test } from './chunks/artifact.DC5WoEgy.js'; | ||
| export { expectTypeOf } from 'expect-type'; | ||
@@ -8,18 +8,13 @@ import * as chai from 'chai'; | ||
| import './chunks/utils.DYj33du9.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '@vitest/spy'; | ||
| import '@vitest/utils/helpers'; | ||
| import '@vitest/utils/offset'; | ||
| import '@vitest/utils/source-map'; | ||
| import './chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/diff'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/error'; | ||
| import './chunks/source-map.DZdIqpIJ.js'; | ||
| import './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import './chunks/spy.B8mHA9qu.js'; | ||
| import './chunks/display.CYwyMF4S.js'; | ||
| import './chunks/index.DzTmMrSM.js'; | ||
| import './chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import './task-utils.js'; | ||
| import 'pathe'; | ||
| import './chunks/plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| import './chunks/plugins.CsoX-42X.js'; | ||
| import './chunks/offset.Dy-5Fdfn.js'; | ||
| import 'tinybench'; | ||
| import 'vite/module-runner'; | ||
| import './chunks/index.Chj8NDwU.js'; |
| import { ModuleEvaluator, ModuleRunnerImportMeta, ModuleRunnerContext, EvaluatedModuleNode } from 'vite/module-runner'; | ||
| import { a as RuntimeRPC, G as GetterTracker } from './chunks/rpc.d.C6-dGZ2f.js'; | ||
| import { a as RuntimeRPC, G as GetterTracker } from './chunks/rpc.d.BeasqWpO.js'; | ||
| import { V as VitestEvaluatedModules } from './chunks/evaluatedModules.d.BxJ5omdx.js'; | ||
| import vm from 'node:vm'; | ||
| import './chunks/config.d.CKWK3nld.js'; | ||
| import '@vitest/pretty-format'; | ||
| import '@vitest/utils'; | ||
| import '@vitest/utils/diff'; | ||
| import '@vitest/spy'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/display'; | ||
| import './chunks/config.d.DsC1jkby.js'; | ||
| import 'vitest/optional-runtime-types.js'; | ||
| import 'tinybench'; | ||
@@ -25,2 +20,26 @@ | ||
| /** | ||
| * Worker-wide cache of V8 code cache buffers for externalized modules. | ||
| * | ||
| * vm pools create a fresh executor per test file, so every externalized | ||
| * module is compiled and evaluated again in each fresh context. The compiled | ||
| * code has no per-context state — reusing its V8 code cache skips the | ||
| * re-parse/re-compile while the evaluation still happens per context. | ||
| * | ||
| * Entries are keyed by the module identifier and guarded by the exact source | ||
| * text, so an invalidated module that produces different code simply replaces | ||
| * its entry. | ||
| */ | ||
| declare class CodeCache { | ||
| private entries; | ||
| get(identifier: string, source: string): Buffer | undefined; | ||
| /** | ||
| * Stores the code cache produced by `produce` unless an entry for the same | ||
| * source already exists. A `produce` failure is recorded as an empty entry, | ||
| * so it is not retried on every fresh context. | ||
| */ | ||
| store(identifier: string, source: string, produce: () => Buffer): void; | ||
| delete(identifier: string): void; | ||
| } | ||
| declare class FileMap { | ||
@@ -56,2 +75,5 @@ private fsCache; | ||
| fileMap: FileMap; | ||
| codeCache?: CodeCache; | ||
| resolveCache?: Map<string, string>; | ||
| moduleInfoCache?: Map<string, ModuleInformation>; | ||
| packageCache: Map<string, any>; | ||
@@ -62,2 +84,8 @@ transform: RuntimeRPC["transform"]; | ||
| } | ||
| interface ModuleInformation { | ||
| type: "data" | "builtin" | "vite" | "wasm" | "module" | "commonjs" | "network"; | ||
| url: string; | ||
| path: string; | ||
| exists?: boolean; | ||
| } | ||
| declare class ExternalModulesExecutor { | ||
@@ -71,2 +99,3 @@ #private; | ||
| private fs; | ||
| readonly codeCache: CodeCache | undefined; | ||
| private resolvers; | ||
@@ -81,2 +110,3 @@ constructor(options: ExternalModulesExecutorOptions); | ||
| private getModuleInformation; | ||
| private resolveModuleInformation; | ||
| private createModule; | ||
@@ -111,3 +141,5 @@ private get isNetworkSupported(); | ||
| evaluatedModules?: VitestEvaluatedModules; | ||
| metaEnv?: ModuleRunnerImportMeta["env"]; | ||
| interopDefault?: boolean | undefined; | ||
| injectCjsGlobals?: boolean | undefined; | ||
| moduleExecutionInfo?: ModuleExecutionInfo; | ||
@@ -114,0 +146,0 @@ getCurrentTestFilepath?: () => string | undefined; |
+66
-22
@@ -35,5 +35,20 @@ import { isBuiltin, createRequire } from 'node:module'; | ||
| const isWindows = process.platform === "win32"; | ||
| // Compiled scripts of inlined modules, shared across vm contexts: vm pools | ||
| // evaluate every module again in each fresh context, but the compiled script | ||
| // holds no per-context state (Vite rewrites dynamic imports to | ||
| // `__vite_ssr_dynamic_import__`, so no per-context import callback is baked | ||
| // in) — only its evaluation has to happen per context. Keyed by module id | ||
| // (`mock:` ids stay distinct from their originals). | ||
| const vmInlineScriptCache = /* @__PURE__ */ new Map(); | ||
| function getVmInlineScript(id, wrappedCode, options) { | ||
| let script = vmInlineScriptCache.get(id); | ||
| if (!script) { | ||
| script = new vm.Script(wrappedCode, options); | ||
| vmInlineScriptCache.set(id, script); | ||
| } | ||
| return script; | ||
| } | ||
| class VitestModuleEvaluator { | ||
| stubs = {}; | ||
| env = createImportMetaEnvProxy(); | ||
| env; | ||
| vm; | ||
@@ -51,2 +66,3 @@ compiledFunctionArgumentsNames; | ||
| this._otel = options.traces || new Traces({ enabled: false }); | ||
| this.env = options.metaEnv ?? createImportMetaEnvProxy(); | ||
| this.vm = vmOptions; | ||
@@ -176,2 +192,10 @@ this.stubs = getDefaultRequestStubs(vmOptions?.context); | ||
| span.setAttribute("code.file.path", meta.filename); | ||
| const __vite_ssr_exportName__ = context.__vite_ssr_exportName__ || ((name, getter) => Object.defineProperty(context[ssrModuleExportsKey], name, { | ||
| enumerable: true, | ||
| configurable: true, | ||
| get: getter | ||
| })); | ||
| let __vite_track_exportName__; | ||
| const getterTracker = this.getterTracker; | ||
| if (getterTracker) __vite_track_exportName__ = getterTracker.createTracker(module.id, __vite_ssr_exportName__); | ||
| const argumentsList = [ | ||
@@ -185,14 +209,20 @@ ssrModuleExportsKey, | ||
| ]; | ||
| const cjsGlobals = this._createCJSGlobals(context, module, span); | ||
| argumentsList.push( | ||
| // TODO@discuss deprecate in Vitest 5, remove in Vitest 6(?) | ||
| // backwards compat for vite-node | ||
| // https://github.com/vitest-dev/vitest/issues/10292 | ||
| "__filename", | ||
| "__dirname", | ||
| "module", | ||
| "exports", | ||
| "require" | ||
| ); | ||
| const argumentsValues = [ | ||
| context[ssrModuleExportsKey], | ||
| context[ssrImportMetaKey], | ||
| context[ssrImportKey], | ||
| context[ssrDynamicImportKey], | ||
| context[ssrExportAllKey], | ||
| __vite_track_exportName__ || __vite_ssr_exportName__ | ||
| ]; | ||
| // TODO@discuss switch the default in Vitest 6(?) | ||
| // backwards compat for vite-node | ||
| const injectCjsGlobals = this.options.injectCjsGlobals !== false || module.meta?.moduleType === "cjs"; | ||
| if (injectCjsGlobals) { | ||
| const cjsGlobals = this._createCJSGlobals(context, module, span); | ||
| argumentsList.push("__filename", "__dirname", "module", "exports", "require"); | ||
| argumentsValues.push(cjsGlobals.__filename, cjsGlobals.__dirname, cjsGlobals.module, cjsGlobals.exports, cjsGlobals.require); | ||
| } | ||
| if (this.compiledFunctionArgumentsNames) argumentsList.push(...this.compiledFunctionArgumentsNames); | ||
| if (this.compiledFunctionArgumentsValues) argumentsValues.push(...this.compiledFunctionArgumentsValues); | ||
| span.setAttribute("vitest.module.arguments", argumentsList); | ||
@@ -221,12 +251,6 @@ // add 'use strict' since ESM enables it by default | ||
| try { | ||
| const initModule = this.vm ? vm.runInContext(wrappedCode, this.vm.context, options) : vm.runInThisContext(wrappedCode, options); | ||
| const __vite_ssr_exportName__ = context.__vite_ssr_exportName__ || ((name, getter) => Object.defineProperty(context[ssrModuleExportsKey], name, { | ||
| enumerable: true, | ||
| configurable: true, | ||
| get: getter | ||
| })); | ||
| let __vite_track_exportName__; | ||
| const getterTracker = this.getterTracker; | ||
| if (getterTracker) __vite_track_exportName__ = getterTracker.createTracker(module.id, __vite_ssr_exportName__); | ||
| await initModule(context[ssrModuleExportsKey], context[ssrImportMetaKey], context[ssrImportKey], context[ssrDynamicImportKey], context[ssrExportAllKey], __vite_track_exportName__ || __vite_ssr_exportName__, cjsGlobals.__filename, cjsGlobals.__dirname, cjsGlobals.module, cjsGlobals.exports, cjsGlobals.require, ...this.compiledFunctionArgumentsValues); | ||
| await (this.vm ? getVmInlineScript(module.id, wrappedCode, options).runInContext(this.vm.context) : vm.runInThisContext(wrappedCode, options))(...argumentsValues); | ||
| } catch (error) { | ||
| if (!injectCjsGlobals) throw enhanceMissingCjsGlobalsError(error); | ||
| throw error; | ||
| } finally { | ||
@@ -358,2 +382,22 @@ // moduleExecutionInfo needs to use Node filename instead of the normalized one | ||
| } | ||
| const CJS_GLOBALS_REFERENCE_ERROR_RE = /^(module|exports|require|__filename|__dirname) is not defined$/; | ||
| const ESM_HINTS = { | ||
| module: "use \"export\" declarations instead of \"module.exports\"", | ||
| exports: "use \"export\" declarations instead of \"exports\"", | ||
| require: "use \"import\" declarations or \"createRequire(import.meta.url)\" instead of \"require\"", | ||
| __filename: "use \"import.meta.filename\" instead of \"__filename\"", | ||
| __dirname: "use \"import.meta.dirname\" instead of \"__dirname\"" | ||
| }; | ||
| function enhanceMissingCjsGlobalsError(error) { | ||
| if (error == null || typeof error !== "object") return error; | ||
| const referenceError = error; | ||
| if (referenceError.name !== "ReferenceError" || typeof referenceError.message !== "string") return error; | ||
| // the message is anchored, so already enhanced errors are not enhanced twice | ||
| const name = referenceError.message.match(CJS_GLOBALS_REFERENCE_ERROR_RE)?.[1]; | ||
| if (!name) return error; | ||
| const message = `${referenceError.message}\n\n"${name}" is a CommonJS variable that is not available in ES modules, and "injectCjsGlobals" is disabled. If this module is meant to be an ES module, ${ESM_HINTS[name]}. If it is meant to be a CommonJS module, use the ".cjs" file extension, set "type": "commonjs" in the nearest package.json, or externalize it with "server.deps.external".`; | ||
| if (typeof referenceError.stack === "string") referenceError.stack = referenceError.stack.replace(referenceError.message, message); | ||
| referenceError.message = message; | ||
| return error; | ||
| } | ||
| const VALID_ID_PREFIX = `/@id/`; | ||
@@ -360,0 +404,0 @@ const NULL_BYTE_PLACEHOLDER = `__x00__`; |
+210
-82
| import * as vite from 'vite'; | ||
| import { InlineConfig, UserConfig as UserConfig$1, TransformResult, Plugin, ResolvedConfig as ResolvedConfig$1, ViteDevServer, LogLevel, LoggerOptions, Logger as Logger$1 } from 'vite'; | ||
| import { UserConfig as UserConfig$1, ResolvedConfig as ResolvedConfig$1, TransformResult, ViteDevServer, LogLevel, LoggerOptions, Logger as Logger$1 } from 'vite'; | ||
| export { vite as Vite }; | ||
| export { esbuildVersion, isCSSRequest, isFileLoadingAllowed, parseAst, parseAstAsync, rollupVersion, version as viteVersion } from 'vite'; | ||
| import { IncomingMessage } from 'node:http'; | ||
| import { R as ResolvedConfig, U as UserConfig, V as VitestOptions, a as Vitest, b as VitestRunMode, A as ApiConfig, L as Logger, c as ResolvedCoverageOptions, C as CoverageMap, d as ReportContext, T as TestProject, e as TestSpecification, P as PoolWorker, f as PoolOptions, W as WorkerRequest, g as TestSequencer } from './chunks/plugin.d.Bpge8Jye.js'; | ||
| export { M as AgentReporter, B as BaseCoverageOptions, h as BaseReporter, i as BenchmarkUserOptions, j as BrowserBuiltinProvider, k as BrowserCommand, l as BrowserCommandContext, m as BrowserConfigOptions, n as BrowserInstanceOption, o as BrowserModuleMocker, p as BrowserOrchestrator, q as BrowserProvider, r as BrowserProviderOption, s as BrowserScript, t as BrowserServerFactory, u as BrowserServerOptions, v as BrowserServerState, w as BrowserServerStateSession, x as BuiltinEnvironment, y as BuiltinReporterOptions, z as BuiltinReporters, D as CSSModuleScopeStrategy, E as CacheKeyIdGenerator, F as CacheKeyIdGeneratorContext, G as CoverageInstrumenter, H as CoverageIstanbulOptions, I as CoverageOptions, J as CoverageProvider, K as CoverageProviderModule, N as CoverageReporter, O as CoverageV8Options, Q as CustomProviderOptions, S as DefaultReporter, X as DepsOptimizationOptions, Y as DotReporter, Z as EnvironmentOptions, _ as GithubActionsReporter, $ as HTMLOptions, a0 as HangingProcessReporter, a1 as InlineConfig, a2 as InstrumenterOptions, a3 as JUnitOptions, a4 as JUnitReporter, a5 as JsonAssertionResult, a6 as JsonOptions, a7 as JsonReporter, a8 as JsonTestResult, a9 as JsonTestResults, M as MinimalReporter, aa as ModuleDiagnostic, ab as OnServerRestartHandler, ac as OnTestsRerunHandler, ad as ParentProjectBrowser, ae as Pool, af as PoolRunnerInitializer, ag as PoolTask, ah as ProjectBrowser, ai as ProjectConfig, aj as Report, ak as ReportedHookContext, al as Reporter, am as ReportersMap, an as ResolveSnapshotPathHandler, ao as ResolveSnapshotPathHandlerContext, ap as ResolvedBrowserOptions, aq as ResolvedProjectConfig, ar as SerializedTestProject, as as TapFlatReporter, at as TapReporter, au as TaskOptions, av as TestCase, aw as TestCollection, ax as TestDiagnostic, ay as TestModule, az as TestModuleState, aA as TestResult, aB as TestResultFailed, aC as TestResultPassed, aD as TestResultSkipped, aE as TestRunEndReason, aF as TestRunResult, aG as TestSequencerConstructor, aH as TestSpecificationOptions, aI as TestState, aJ as TestSuite, aK as TestSuiteState, aL as ToMatchScreenshotComparators, aM as ToMatchScreenshotOptions, aN as TypecheckConfig, aO as UserWorkspaceConfig, aP as VerboseReporter, aQ as VitestEnvironment, aR as VitestPackageInstaller, aS as VitestPluginContext, aT as WatcherTriggerPattern, aU as WorkerResponse, aV as _BrowserNames, aW as experimental_getRunnerTask } from './chunks/plugin.d.Bpge8Jye.js'; | ||
| import { u as AfterSuiteRunMeta } from './chunks/config.d.CKWK3nld.js'; | ||
| export { p as RunnerTask, a2 as RunnerTaskResult, b as RunnerTaskResultPack, d as RunnerTestCase, F as RunnerTestFile, l as RunnerTestSuite, a3 as RuntimeConfig, aC as SequenceHooks, aD as SequenceSetupFiles } from './chunks/config.d.CKWK3nld.js'; | ||
| import { Awaitable } from '@vitest/utils'; | ||
| export { SerializedError } from '@vitest/utils'; | ||
| import { a as RuntimeRPC } from './chunks/rpc.d.C6-dGZ2f.js'; | ||
| import { R as ResolvedConfig, C as CliOptions, U as UserConfig, L as Logger, A as ApiConfig, P as PluginHarness, V as Vitest, a as ResolvedCoverageOptions, b as CoverageMap, c as ReportContext, T as TestProject, d as VitestOptions, e as VitestRunMode, f as TestSpecification, g as PoolWorker, h as PoolOptions, W as WorkerRequest, i as TestSequencer } from './chunks/plugin.d.BOjbmxWW.js'; | ||
| export { M as AgentReporter, B as BaseCoverageOptions, j as BaseReporter, k as BenchmarkUserOptions, l as BrowserBuiltinProvider, m as BrowserCommand, n as BrowserCommandContext, o as BrowserConfigOptions, p as BrowserInstanceOption, q as BrowserModuleMocker, r as BrowserOrchestrator, s as BrowserProvider, t as BrowserProviderOption, u as BrowserScript, v as BrowserServerContribution, w as BrowserServerFactory, x as BrowserServerState, y as BrowserServerStateSession, z as BuiltinEnvironment, D as BuiltinReporterOptions, E as BuiltinReporters, F as CSSModuleScopeStrategy, G as CacheKeyIdGenerator, H as CacheKeyIdGeneratorContext, I as CoverageInstrumenter, J as CoverageIstanbulOptions, K as CoverageOptions, N as CoverageProvider, O as CoverageProviderModule, Q as CoverageReporter, S as CoverageV8Options, X as CustomProviderOptions, Y as DefaultReporter, Z as DepsOptimizationOptions, _ as DotReporter, $ as EnvironmentOptions, a0 as GithubActionsReporter, a1 as HTMLOptions, a2 as HangingProcessReporter, a3 as InlineConfig, a4 as InstrumenterOptions, a5 as JUnitOptions, a6 as JUnitReporter, a7 as JsonAssertionResult, a8 as JsonOptions, a9 as JsonReporter, aa as JsonTestResult, ab as JsonTestResults, M as MinimalReporter, ac as ModuleDiagnostic, ad as OnServerRestartHandler, ae as OnTestsRerunHandler, af as ParentProjectBrowser, ag as Pool, ah as PoolRunnerInitializer, ai as PoolTask, aj as ProjectBrowser, ak as ProjectConfig, al as Report, am as ReportedHookContext, an as Reporter, ao as ReportersMap, ap as ResolveSnapshotPathHandler, aq as ResolveSnapshotPathHandlerContext, ar as ResolvedBrowserOptions, as as ResolvedProjectConfig, at as SerializedTestProject, au as TapFlatReporter, av as TapReporter, aw as TaskOptions, ax as TestCase, ay as TestCollection, az as TestDiagnostic, aA as TestModule, aB as TestModuleState, aC as TestResult, aD as TestResultFailed, aE as TestResultPassed, aF as TestResultSkipped, aG as TestRunEndReason, aH as TestRunResult, aI as TestSequencerConstructor, aJ as TestSpecificationOptions, aK as TestState, aL as TestSuite, aM as TestSuiteState, aN as ToMatchScreenshotComparators, aO as ToMatchScreenshotOptions, aP as TypecheckConfig, aQ as UserWorkspaceConfig, aR as VerboseReporter, aS as VitestEnvironment, aT as VitestPackageInstaller, aU as VitestPluginContext, aV as WatcherTriggerPattern, aW as WorkerResponse, aX as _BrowserNames, aY as experimental_getRunnerTask, aZ as startVitest } from './chunks/plugin.d.BOjbmxWW.js'; | ||
| import { K as AfterSuiteRunMeta, A as Awaitable } from './chunks/config.d.DsC1jkby.js'; | ||
| export { z as RunnerTask, ax as RunnerTaskResult, b as RunnerTaskResultPack, d as RunnerTestCase, F as RunnerTestFile, v as RunnerTestSuite, ay as RuntimeConfig, b7 as SequenceHooks, b8 as SequenceSetupFiles, aA as SerializedError, b9 as disableDefaultColors } from './chunks/config.d.DsC1jkby.js'; | ||
| import { EventEmitter } from 'events'; | ||
| import { a as RuntimeRPC } from './chunks/rpc.d.BeasqWpO.js'; | ||
| import { Writable } from 'node:stream'; | ||
| import { C as ContextRPC } from './chunks/worker.d.JES7ffPK.js'; | ||
| export { T as TestExecutionType } from './chunks/worker.d.JES7ffPK.js'; | ||
| import { C as ContextRPC } from './chunks/worker.d.s_RdeZtI.js'; | ||
| export { T as TestExecutionType } from './chunks/worker.d.s_RdeZtI.js'; | ||
| import { Debugger } from 'obug'; | ||
| export { g as generateFileHash } from './chunks/task-utils.d.mMDXJF_I.js'; | ||
| export { g as generateFileHash } from './chunks/task-utils.d.BKHiHxSN.js'; | ||
| export { CDPSession } from 'vitest/browser'; | ||
| import './chunks/browser.d.DoM6vBOs.js'; | ||
| import 'node:fs/promises'; | ||
| import '@vitest/pretty-format'; | ||
| import '@vitest/utils/diff'; | ||
| import './chunks/browser.d.BFOby8YL.js'; | ||
| import 'chai'; | ||
| import 'vitest/optional-types.js'; | ||
| import '@vitest/mocker'; | ||
| import '@vitest/utils/source-map'; | ||
| import './chunks/coverage.d.CCNrKR65.js'; | ||
| import './chunks/coverage.d.ByaAMV4A.js'; | ||
| import 'node:console'; | ||
| import 'node:fs/promises'; | ||
| import 'node:fs'; | ||
| import '@vitest/spy'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/display'; | ||
| import 'vitest/optional-runtime-types.js'; | ||
| import 'tinybench'; | ||
| import 'vite/module-runner'; | ||
| import './chunks/environment.d.CrsxCzP1.js'; | ||
| import './chunks/environment.d.4-rzQgpt.js'; | ||
@@ -65,53 +59,188 @@ declare function escapeTestName(label: string, dynamic: boolean): string; | ||
| interface CliOptions extends UserConfig { | ||
| /** | ||
| * Override the watch mode | ||
| */ | ||
| run?: boolean; | ||
| /** | ||
| * Removes colors from the console output | ||
| */ | ||
| color?: boolean; | ||
| /** | ||
| * Output collected tests as JSON or to a file | ||
| */ | ||
| json?: string | boolean; | ||
| /** | ||
| * Output collected test files only | ||
| */ | ||
| filesOnly?: boolean; | ||
| /** | ||
| * Parse files statically instead of running them to collect tests | ||
| * @experimental | ||
| */ | ||
| staticParse?: boolean; | ||
| /** | ||
| * How many tests to process at the same time | ||
| * @experimental | ||
| */ | ||
| staticParseConcurrency?: number; | ||
| /** | ||
| * Override vite config's configLoader from CLI. | ||
| * Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly (default: `bundle`). | ||
| * This is only available with **vite version 6.1.0** and above. | ||
| * @experimental | ||
| */ | ||
| configLoader?: InlineConfig extends { | ||
| configLoader?: infer T; | ||
| } ? T : never; | ||
| interface OptionConfig { | ||
| default?: any; | ||
| type?: any; | ||
| } | ||
| /** | ||
| * Start Vitest programmatically | ||
| * | ||
| * Returns a Vitest instance if initialized successfully. | ||
| */ | ||
| declare function startVitest(cliFilters?: string[], options?: CliOptions, viteOverrides?: UserConfig$1, vitestOptions?: VitestOptions): Promise<Vitest>; | ||
| /** | ||
| * @deprecated The `mode` argument is no longer used. Use `startVitest(cliFilters?, options?, viteOverrides?, vitestOptions?)` instead. | ||
| */ | ||
| declare function startVitest(mode: VitestRunMode, cliFilters?: string[], options?: CliOptions, viteOverrides?: UserConfig$1, vitestOptions?: VitestOptions): Promise<Vitest>; | ||
| declare class Option { | ||
| rawName: string; | ||
| description: string; | ||
| /** Option name */ | ||
| name: string; | ||
| /** Option name and aliases */ | ||
| names: string[]; | ||
| isBoolean?: boolean; | ||
| required?: boolean; | ||
| config: OptionConfig; | ||
| negated: boolean; | ||
| constructor(rawName: string, description: string, config?: OptionConfig); | ||
| } | ||
| interface CommandArg { | ||
| required: boolean; | ||
| value: string; | ||
| variadic: boolean; | ||
| } | ||
| interface HelpSection { | ||
| title?: string; | ||
| body: string; | ||
| } | ||
| interface CommandConfig { | ||
| allowUnknownOptions?: boolean; | ||
| ignoreOptionDefaultValue?: boolean; | ||
| } | ||
| declare type HelpCallback = (sections: HelpSection[]) => void | HelpSection[]; | ||
| declare type CommandExample = ((bin: string) => string) | string; | ||
| declare class Command { | ||
| rawName: string; | ||
| description: string; | ||
| config: CommandConfig; | ||
| cli: CAC; | ||
| options: Option[]; | ||
| aliasNames: string[]; | ||
| name: string; | ||
| args: CommandArg[]; | ||
| commandAction?: (...args: any[]) => any; | ||
| usageText?: string; | ||
| versionNumber?: string; | ||
| examples: CommandExample[]; | ||
| helpCallback?: HelpCallback; | ||
| globalCommand?: GlobalCommand; | ||
| constructor(rawName: string, description: string, config: CommandConfig, cli: CAC); | ||
| usage(text: string): this; | ||
| allowUnknownOptions(): this; | ||
| ignoreOptionDefaultValue(): this; | ||
| version(version: string, customFlags?: string): this; | ||
| example(example: CommandExample): this; | ||
| /** | ||
| * Add a option for this command | ||
| * @param rawName Raw option name(s) | ||
| * @param description Option description | ||
| * @param config Option config | ||
| */ | ||
| option(rawName: string, description: string, config?: OptionConfig): this; | ||
| alias(name: string): this; | ||
| action(callback: (...args: any[]) => any): this; | ||
| /** | ||
| * Check if a command name is matched by this command | ||
| * @param name Command name | ||
| */ | ||
| isMatched(name: string): boolean; | ||
| get isDefaultCommand(): boolean; | ||
| get isGlobalCommand(): boolean; | ||
| /** | ||
| * Check if an option is registered in this command | ||
| * @param name Option name | ||
| */ | ||
| hasOption(name: string): Option | undefined; | ||
| outputHelp(): void; | ||
| outputVersion(): void; | ||
| checkRequiredArgs(): void; | ||
| /** | ||
| * Check if the parsed options contain any unknown options | ||
| * | ||
| * Exit and output error when true | ||
| */ | ||
| checkUnknownOptions(): void; | ||
| /** | ||
| * Check if the required string-type options exist | ||
| */ | ||
| checkOptionValue(): void; | ||
| } | ||
| declare class GlobalCommand extends Command { | ||
| constructor(cli: CAC); | ||
| } | ||
| interface ParsedArgv { | ||
| args: ReadonlyArray<string>; | ||
| options: { | ||
| [k: string]: any; | ||
| }; | ||
| } | ||
| declare class CAC extends EventEmitter { | ||
| /** The program name to display in help and version message */ | ||
| name: string; | ||
| commands: Command[]; | ||
| globalCommand: GlobalCommand; | ||
| matchedCommand?: Command; | ||
| matchedCommandName?: string; | ||
| /** | ||
| * Raw CLI arguments | ||
| */ | ||
| rawArgs: string[]; | ||
| /** | ||
| * Parsed CLI arguments | ||
| */ | ||
| args: ParsedArgv['args']; | ||
| /** | ||
| * Parsed CLI options, camelCased | ||
| */ | ||
| options: ParsedArgv['options']; | ||
| showHelpOnExit?: boolean; | ||
| showVersionOnExit?: boolean; | ||
| /** | ||
| * @param name The program name to display in help and version message | ||
| */ | ||
| constructor(name?: string); | ||
| /** | ||
| * Add a global usage text. | ||
| * | ||
| * This is not used by sub-commands. | ||
| */ | ||
| usage(text: string): this; | ||
| /** | ||
| * Add a sub-command | ||
| */ | ||
| command(rawName: string, description?: string, config?: CommandConfig): Command; | ||
| /** | ||
| * Add a global CLI option. | ||
| * | ||
| * Which is also applied to sub-commands. | ||
| */ | ||
| option(rawName: string, description: string, config?: OptionConfig): this; | ||
| /** | ||
| * Show help message when `-h, --help` flags appear. | ||
| * | ||
| */ | ||
| help(callback?: HelpCallback): this; | ||
| /** | ||
| * Show version number when `-v, --version` flags appear. | ||
| * | ||
| */ | ||
| version(version: string, customFlags?: string): this; | ||
| /** | ||
| * Add a global example. | ||
| * | ||
| * This example added here will not be used by sub-commands. | ||
| */ | ||
| example(example: CommandExample): this; | ||
| /** | ||
| * Output the corresponding help message | ||
| * When a sub-command is matched, output the help message for the command | ||
| * Otherwise output the global one. | ||
| * | ||
| */ | ||
| outputHelp(): void; | ||
| /** | ||
| * Output the version number. | ||
| * | ||
| */ | ||
| outputVersion(): void; | ||
| private setParsedInfo; | ||
| unsetMatchedCommand(): void; | ||
| /** | ||
| * Parse argv | ||
| */ | ||
| parse(argv?: string[], { | ||
| /** Whether to run the action for matched command */ | ||
| run, }?: { | ||
| run?: boolean | undefined; | ||
| }): ParsedArgv; | ||
| private mri; | ||
| runMatchedCommand(): any; | ||
| } | ||
| interface CliParseOptions { | ||
| allowUnknownOptions?: boolean; | ||
| } | ||
| declare function createCLI(options?: CliParseOptions): CAC; | ||
| declare function parseCLI(argv: string | string[], config?: CliParseOptions): { | ||
@@ -122,6 +251,4 @@ filter: string[]; | ||
| /** | ||
| * @deprecated Internal function | ||
| */ | ||
| declare function resolveApiServerConfig<Options extends ApiConfig & Omit<UserConfig, "expect">>(options: Options, defaultPort: number, parentApi?: ApiConfig, logger?: Logger): ApiConfig | undefined; | ||
| declare function resolveApiServerConfig(config: UserConfig, defaultPort: number, logger: Logger): ApiConfig; | ||
| declare function resolveConfig(options?: UserConfig, viteOverrides?: UserConfig$1, pluginsHarness?: PluginHarness): Promise<ResolvedConfig$1>; | ||
@@ -164,4 +291,7 @@ type Threshold = "lines" | "functions" | "statements" | "branches"; | ||
| autoUpdateMarker: string; | ||
| globMatchers?: { | ||
| matchExclude: (file: string) => boolean; | ||
| matchInclude: (file: string) => boolean; | ||
| }; | ||
| coverageFiles: CoverageFiles; | ||
| pendingPromises: Promise<void>[]; | ||
| coverageFilesDirectory: string; | ||
@@ -176,2 +306,8 @@ reportsDirectoryLock: ReportsDirectoryLock; | ||
| isIncluded(_filename: string, root?: string): boolean; | ||
| /** | ||
| * Compile `coverage.include`/`coverage.exclude` into reusable matchers once. | ||
| * `picomatch.isMatch(file, patterns, options)` recompiles the patterns on | ||
| * every call, which dominates the filtering step on large test suites. | ||
| */ | ||
| private getGlobMatchers; | ||
| private getUntestedFilesByRoot; | ||
@@ -188,3 +324,2 @@ getUntestedFiles(testedFiles: string[]): Promise<string[]>; | ||
| clean(clean?: boolean): Promise<void>; | ||
| private normalizeCoverageFileError; | ||
| onAfterSuiteRun({ coverage, environment, projectName, testFiles }: AfterSuiteRunMeta): void; | ||
@@ -256,9 +391,2 @@ readCoverageFiles<CoverageType>({ onFileRead, onFinished, onDebug }: { | ||
| declare function VitestPlugin(options?: UserConfig, vitest?: Vitest): Promise<Plugin[]>; | ||
| declare function resolveConfig(options?: UserConfig, viteOverrides?: UserConfig$1): Promise<{ | ||
| vitestConfig: ResolvedConfig; | ||
| viteConfig: ResolvedConfig$1; | ||
| }>; | ||
| declare function resolveFsAllow(projectRoot: string, rootConfigFile: string | false | undefined): string[]; | ||
@@ -385,3 +513,3 @@ | ||
| export { ApiConfig, BaseCoverageProvider, BaseSequencer, ForksPoolWorker, GitNotFoundError, PoolOptions, PoolWorker, ReportContext, ResolvedConfig, ResolvedCoverageOptions, TestProject, TestSequencer, TestSpecification, UserConfig as TestUserConfig, FilesNotFoundError as TestsNotFoundError, ThreadsPoolWorker, TypecheckPoolWorker, Vitest, VitestOptions, VitestPlugin, VitestRunMode, VmForksPoolWorker, VmThreadsPoolWorker, WorkerRequest, createDebugger, createMethodsRPC, createViteLogger, createViteServer, createVitest, distDir, escapeTestName, getFilePoolName, isFileServingAllowed, isValidApiRequest, parseCLI, registerConsoleShortcuts, resolveApiServerConfig, resolveConfig, resolveFsAllow, rolldownVersion, rootDir, startVitest, version }; | ||
| export type { CliOptions, CliParseOptions, ProcessPool, CollectLineNumbers as TypeCheckCollectLineNumbers, CollectLines as TypeCheckCollectLines, Context as TypeCheckContext, TscErrorInfo as TypeCheckErrorInfo, RawErrsMap as TypeCheckRawErrorsMap, RootAndTarget as TypeCheckRootAndTarget, WorkerContext }; | ||
| export { ApiConfig, BaseCoverageProvider, BaseSequencer, CliOptions, ForksPoolWorker, GitNotFoundError, Logger, PluginHarness, PoolOptions, PoolWorker, ReportContext, ResolvedConfig, ResolvedCoverageOptions, TestProject, TestSequencer, TestSpecification, UserConfig as TestUserConfig, FilesNotFoundError as TestsNotFoundError, ThreadsPoolWorker, TypecheckPoolWorker, Vitest, VitestOptions, VitestRunMode, VmForksPoolWorker, VmThreadsPoolWorker, WorkerRequest, createCLI, createDebugger, createMethodsRPC, createViteLogger, createViteServer, createVitest, distDir, escapeTestName, getFilePoolName, isFileServingAllowed, isValidApiRequest, parseCLI, registerConsoleShortcuts, resolveApiServerConfig, resolveConfig, resolveFsAllow, rolldownVersion, rootDir, version }; | ||
| export type { CliParseOptions, ProcessPool, CollectLineNumbers as TypeCheckCollectLineNumbers, CollectLines as TypeCheckCollectLines, Context as TypeCheckContext, TscErrorInfo as TypeCheckErrorInfo, RawErrsMap as TypeCheckRawErrorsMap, RootAndTarget as TypeCheckRootAndTarget, WorkerContext }; |
+29
-66
| import * as vite from 'vite'; | ||
| import { resolveConfig as resolveConfig$1, mergeConfig } from 'vite'; | ||
| export { esbuildVersion, isCSSRequest, isFileLoadingAllowed, parseAst, parseAstAsync, rollupVersion, version as viteVersion } from 'vite'; | ||
| import { V as Vitest, a as VitestPlugin } from './chunks/cli-api.cZcvaUFI.js'; | ||
| export { M as AgentReporter, B as BaseCoverageProvider, D as DefaultReporter, b as DotReporter, F as ForksPoolWorker, G as GitNotFoundError, c as GithubActionsReporter, H as HangingProcessReporter, J as JUnitReporter, d as JsonReporter, M as MinimalReporter, R as ReportersMap, T as TapFlatReporter, e as TapReporter, f as TestsNotFoundError, g as ThreadsPoolWorker, h as TypecheckPoolWorker, i as VerboseReporter, j as VitestPackageInstaller, k as VmForksPoolWorker, l as VmThreadsPoolWorker, m as createDebugger, n as createMethodsRPC, o as createViteLogger, p as createVitest, q as escapeTestName, r as experimental_getRunnerTask, s as getFilePoolName, t as isFileServingAllowed, u as isValidApiRequest, v as registerConsoleShortcuts, w as resolveFsAllow, x as startVitest } from './chunks/cli-api.cZcvaUFI.js'; | ||
| export { p as parseCLI } from './chunks/cac.DKrA6qEB.js'; | ||
| import { f as findConfigFile, r as resolveConfig$2 } from './chunks/index.Djaij2xr.js'; | ||
| export { B as BaseSequencer, a as resolveApiServerConfig } from './chunks/index.Djaij2xr.js'; | ||
| import { slash, deepClone } from '@vitest/utils/helpers'; | ||
| import { resolve } from 'pathe'; | ||
| import { V as Vitest } from './chunks/index.5krd73UD.js'; | ||
| export { M as AgentReporter, B as BaseCoverageProvider, a as BaseSequencer, D as DefaultReporter, b as DotReporter, F as ForksPoolWorker, G as GitNotFoundError, c as GithubActionsReporter, H as HangingProcessReporter, J as JUnitReporter, d as JsonReporter, L as Logger, M as MinimalReporter, P as PluginHarness, R as ReportersMap, T as TapFlatReporter, e as TapReporter, f as TestsNotFoundError, g as ThreadsPoolWorker, h as TypecheckPoolWorker, i as VerboseReporter, j as VitestPackageInstaller, k as VmForksPoolWorker, l as VmThreadsPoolWorker, m as createDebugger, n as createMethodsRPC, o as createViteLogger, p as escapeTestName, q as experimental_getRunnerTask, r as getFilePoolName, s as isFileServingAllowed, t as resolveApiServerConfig, u as resolveConfig, v as resolveFsAllow } from './chunks/index.5krd73UD.js'; | ||
| export { i as isValidApiRequest } from './chunks/check.Cz_-YojU.js'; | ||
| export { c as createCLI, p as parseCLI } from './chunks/cac.B41kXwyU.js'; | ||
| export { c as createVitest, r as registerConsoleShortcuts, s as startVitest } from './chunks/cli-api.bqNN5viV.js'; | ||
| export { distDir, rootDir } from './path.js'; | ||
| export { generateFileHash } from './task-utils.js'; | ||
| export { m as disableDefaultColors } from './chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import 'node:os'; | ||
| import './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import './chunks/source-map.DZdIqpIJ.js'; | ||
| import './chunks/constants.-juJ8b_4.js'; | ||
| import './chunks/artifact.DC5WoEgy.js'; | ||
| import './chunks/index.DzTmMrSM.js'; | ||
| import './chunks/display.CYwyMF4S.js'; | ||
| import './chunks/nativeModuleRunner.BDnwGb8g.js'; | ||
| import 'node:url'; | ||
| import 'node:fs'; | ||
| import './chunks/coverage.CTzCuANN.js'; | ||
| import 'node:module'; | ||
| import 'node:path'; | ||
| import './chunks/index.CesbTg1C.js'; | ||
| import 'node:module'; | ||
| import 'node:process'; | ||
| import 'node:fs/promises'; | ||
| import 'node:url'; | ||
| import 'node:assert'; | ||
| import 'node:v8'; | ||
| import 'node:util'; | ||
| import 'node:os'; | ||
| import '@vitest/utils/serialize'; | ||
| import './chunks/artifact.BNnEI1sJ.js'; | ||
| import '@vitest/utils/error'; | ||
| import '@vitest/utils/timers'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/source-map'; | ||
| import './chunks/nativeModuleRunner.WlMdOB52.js'; | ||
| import 'vite/module-runner'; | ||
| import './traces.js'; | ||
| import 'obug'; | ||
| import 'tinyrainbow'; | ||
| import 'node:crypto'; | ||
| import 'picomatch'; | ||
| import 'tinyglobby'; | ||
| import './chunks/defaults.B_pFOTYy.js'; | ||
| import './chunks/env.BKKtU2WC.js'; | ||
| import './chunks/defaults.BJUmAuaO.js'; | ||
| import './chunks/env.DzFJjrmK.js'; | ||
| import 'std-env'; | ||
| import '#module-evaluator'; | ||
| import 'magic-string'; | ||
| import '@vitest/mocker/node'; | ||
| import 'node:console'; | ||
| import './chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import 'node:stream'; | ||
| import 'node:perf_hooks'; | ||
| import 'tinyexec'; | ||
| import '@vitest/utils/offset'; | ||
| import './chunks/utils.DKODp04v.js'; | ||
| import './chunks/offset.Dy-5Fdfn.js'; | ||
| import './chunks/utils.CO-iLyCr.js'; | ||
| import '#module-evaluator'; | ||
| import 'picomatch'; | ||
| import './chunks/coverage.BVb1JqW7.js'; | ||
| import './chunks/resolver.CERfsKE-.js'; | ||
| import 'es-module-lexer'; | ||
| import 'node:tty'; | ||
@@ -56,42 +55,6 @@ import 'node:events'; | ||
| import 'node:worker_threads'; | ||
| import 'readline'; | ||
| import 'events'; | ||
| import 'https'; | ||
| import 'http'; | ||
| import 'net'; | ||
| import 'tls'; | ||
| import 'crypto'; | ||
| import 'stream'; | ||
| import 'url'; | ||
| import 'zlib'; | ||
| import 'buffer'; | ||
| import 'util'; | ||
| import './chunks/constants.-juJ8b_4.js'; | ||
| import 'magic-string'; | ||
| import '@vitest/mocker/node'; | ||
| import '@vitest/utils/constants'; | ||
| import '@vitest/utils/resolver'; | ||
| import 'es-module-lexer'; | ||
| import '@vitest/utils/source-map/node'; | ||
| import 'node:readline'; | ||
| import 'readline'; | ||
| // this is only exported as a public function and not used inside vitest | ||
| async function resolveConfig(options = {}, viteOverrides = {}) { | ||
| const root = slash(resolve(options.root || process.cwd())); | ||
| const configPath = options.config === false ? false : options.config ? resolve(root, options.config) : findConfigFile(root); | ||
| options.config = configPath; | ||
| const vitest = new Vitest(deepClone(options)); | ||
| const config = await resolveConfig$1(mergeConfig({ | ||
| configFile: configPath, | ||
| mode: options.mode || "test", | ||
| plugins: [await VitestPlugin(options, vitest)] | ||
| }, mergeConfig(viteOverrides, { root: options.root })), "serve"); | ||
| const vitestConfig = resolveConfig$2(vitest, Reflect.get(config, "_vitest"), config); | ||
| await vitest.close(); | ||
| return { | ||
| viteConfig: config, | ||
| vitestConfig | ||
| }; | ||
| } | ||
| const version = Vitest.version; | ||
@@ -102,2 +65,2 @@ const createViteServer = vite.createServer; | ||
| export { VitestPlugin, createViteServer, resolveConfig, rolldownVersion, version }; | ||
| export { createViteServer, rolldownVersion, version }; |
+5
-10
@@ -1,11 +0,6 @@ | ||
| import { E as Environment } from './chunks/environment.d.CrsxCzP1.js'; | ||
| export { a as EnvironmentReturn, V as VmEnvironmentReturn } from './chunks/environment.d.CrsxCzP1.js'; | ||
| import { aI as SnapshotEnvironment, aJ as SnapshotEnvironmentOptions } from './chunks/config.d.CKWK3nld.js'; | ||
| export { n as SerializedConfig, V as VitestRunner } from './chunks/config.d.CKWK3nld.js'; | ||
| import '@vitest/utils'; | ||
| import '@vitest/pretty-format'; | ||
| import '@vitest/utils/diff'; | ||
| import '@vitest/spy'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/display'; | ||
| import { E as Environment } from './chunks/environment.d.4-rzQgpt.js'; | ||
| export { a as EnvironmentReturn, V as VmEnvironmentReturn } from './chunks/environment.d.4-rzQgpt.js'; | ||
| import { bl as SnapshotEnvironment, bm as SnapshotEnvironmentOptions } from './chunks/config.d.DsC1jkby.js'; | ||
| export { x as SerializedConfig, V as VitestRunner } from './chunks/config.d.DsC1jkby.js'; | ||
| import 'vitest/optional-runtime-types.js'; | ||
| import 'tinybench'; | ||
@@ -12,0 +7,0 @@ |
+4
-5
| import { VitestModuleEvaluator } from './module-evaluator.js'; | ||
| import { V as VITEST_VM_CONTEXT_SYMBOL, s as startVitestModuleRunner, a as VitestModuleRunner } from './chunks/index.DNRmy2jU.js'; | ||
| export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.DNRmy2jU.js'; | ||
| import { V as VITEST_VM_CONTEXT_SYMBOL, s as startVitestModuleRunner, a as VitestModuleRunner } from './chunks/index.DxR-nMjO.js'; | ||
| export { e as builtinEnvironments, p as populateGlobal } from './chunks/index.DxR-nMjO.js'; | ||
| import { g as getWorkerState } from './chunks/utils.DYj33du9.js'; | ||
| export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './chunks/node.C9I1sbE9.js'; | ||
| export { VitestNodeSnapshotEnvironment as VitestSnapshotEnvironment } from './chunks/node.BPMnm_Q2.js'; | ||
| import 'node:module'; | ||
@@ -12,5 +12,4 @@ import 'node:url'; | ||
| import 'node:fs'; | ||
| import '@vitest/utils/helpers'; | ||
| import './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import './chunks/modules.BJuCwlRJ.js'; | ||
| import 'pathe'; | ||
| import './path.js'; | ||
@@ -17,0 +16,0 @@ import 'node:path'; |
+1
-1
@@ -1,1 +0,1 @@ | ||
| export * from '@vitest/spy'; | ||
| export { c as clearAllMocks, d as createMockInstance, f as fn, i as isMockFunction, b as resetAllMocks, r as restoreAllMocks, a as spyOn } from './chunks/spy.B8mHA9qu.js'; |
@@ -1,3 +0,2 @@ | ||
| import { toArray } from '@vitest/utils/helpers'; | ||
| import { relative } from 'pathe'; | ||
| import { t as toArray, a as relative } from './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
@@ -4,0 +3,0 @@ /* @__NO_SIDE_EFFECTS__ */ |
+5
-10
@@ -1,13 +0,8 @@ | ||
| import { W as WorkerGlobalState, d as WorkerSetupContext, e as BirpcOptions } from './chunks/worker.d.JES7ffPK.js'; | ||
| import { T as Traces, a as RuntimeRPC } from './chunks/rpc.d.C6-dGZ2f.js'; | ||
| import { Awaitable } from '@vitest/utils'; | ||
| import { W as WorkerGlobalState, d as WorkerSetupContext, e as BirpcOptions } from './chunks/worker.d.s_RdeZtI.js'; | ||
| import { T as Traces, a as RuntimeRPC } from './chunks/rpc.d.BeasqWpO.js'; | ||
| import { A as Awaitable } from './chunks/config.d.DsC1jkby.js'; | ||
| import { ModuleRunner } from 'vite/module-runner'; | ||
| import './chunks/config.d.CKWK3nld.js'; | ||
| import '@vitest/pretty-format'; | ||
| import '@vitest/utils/diff'; | ||
| import '@vitest/spy'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/display'; | ||
| import './chunks/environment.d.4-rzQgpt.js'; | ||
| import 'vitest/optional-runtime-types.js'; | ||
| import 'tinybench'; | ||
| import './chunks/environment.d.CrsxCzP1.js'; | ||
@@ -14,0 +9,0 @@ /** @experimental */ |
+24
-36
@@ -1,46 +0,35 @@ | ||
| export { r as runBaseTests, s as setupEnvironment } from './chunks/base.BKfXyFN7.js'; | ||
| export { i as init } from './chunks/init.DTAQFCjl.js'; | ||
| export { r as runBaseTests, s as setupEnvironment } from './chunks/base.B0fUxpj9.js'; | ||
| export { i as init } from './chunks/init.CfiYZpFg.js'; | ||
| import 'node:vm'; | ||
| import '@vitest/spy'; | ||
| import './chunks/index.B4UTDegh.js'; | ||
| import './chunks/spy.B8mHA9qu.js'; | ||
| import './chunks/index.JaztIWgW.js'; | ||
| import 'chai'; | ||
| import 'node:async_hooks'; | ||
| import './chunks/setup-common.ZNdeu5wa.js'; | ||
| import './chunks/coverage.CTzCuANN.js'; | ||
| import '@vitest/utils/timers'; | ||
| import './chunks/utils.DYj33du9.js'; | ||
| import './chunks/plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| import './chunks/rpc.DZEh5xnQ.js'; | ||
| import 'pathe'; | ||
| import './chunks/coverage.BfSEMtie.js'; | ||
| import './chunks/coverage.BVb1JqW7.js'; | ||
| import './chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import './chunks/rpc.iNjF664v.js'; | ||
| import 'vite/module-runner'; | ||
| import './chunks/source-map.DZdIqpIJ.js'; | ||
| import './chunks/index.Chj8NDwU.js'; | ||
| import './chunks/index.D6NDM5O1.js'; | ||
| import './chunks/artifact.BNnEI1sJ.js'; | ||
| import '@vitest/utils/error'; | ||
| import '@vitest/utils/helpers'; | ||
| import './chunks/utils.DYj33du9.js'; | ||
| import './chunks/setup-common.vxjAyUtK.js'; | ||
| import './chunks/plugins.CsoX-42X.js'; | ||
| import './chunks/index.DzTmMrSM.js'; | ||
| import './chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import './chunks/index.CLtI1k_4.js'; | ||
| import './chunks/artifact.DC5WoEgy.js'; | ||
| import './chunks/display.CYwyMF4S.js'; | ||
| import './task-utils.js'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/source-map'; | ||
| import '@vitest/utils/offset'; | ||
| import './chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '@vitest/utils/diff'; | ||
| import 'tinyrainbow'; | ||
| import './chunks/offset.Dy-5Fdfn.js'; | ||
| import 'tinybench'; | ||
| import 'expect-type'; | ||
| import './chunks/nativeModuleRunner.WlMdOB52.js'; | ||
| import 'node:url'; | ||
| import './chunks/index.CesbTg1C.js'; | ||
| import './traces.js'; | ||
| import './chunks/index.DxR-nMjO.js'; | ||
| import 'node:fs'; | ||
| import './chunks/modules.BJuCwlRJ.js'; | ||
| import 'node:module'; | ||
| import 'node:url'; | ||
| import './path.js'; | ||
| import 'node:path'; | ||
| import 'node:process'; | ||
| import 'node:fs/promises'; | ||
| import 'node:assert'; | ||
| import 'node:v8'; | ||
| import 'node:util'; | ||
| import './traces.js'; | ||
| import './chunks/index.DNRmy2jU.js'; | ||
| import './chunks/modules.BJuCwlRJ.js'; | ||
| import './path.js'; | ||
| import './module-evaluator.js'; | ||
@@ -54,3 +43,2 @@ import '@vitest/mocker'; | ||
| import 'node:timers/promises'; | ||
| import '@vitest/utils/constants'; | ||
| import '@vitest/utils/serialize'; | ||
| import 'node:util'; |
+21
-33
@@ -1,36 +0,32 @@ | ||
| import { r as runBaseTests, s as setupBaseEnvironment } from '../chunks/base.BKfXyFN7.js'; | ||
| import { w as workerInit } from '../chunks/init-forks.BG4bCDny.js'; | ||
| import { r as runBaseTests, s as setupBaseEnvironment } from '../chunks/base.B0fUxpj9.js'; | ||
| import { w as workerInit } from '../chunks/init-forks.CXzT841o.js'; | ||
| import 'node:vm'; | ||
| import '@vitest/spy'; | ||
| import '../chunks/index.B4UTDegh.js'; | ||
| import '../chunks/spy.B8mHA9qu.js'; | ||
| import '../chunks/index.JaztIWgW.js'; | ||
| import 'chai'; | ||
| import 'node:async_hooks'; | ||
| import '../chunks/setup-common.ZNdeu5wa.js'; | ||
| import '../chunks/coverage.CTzCuANN.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '../chunks/utils.DYj33du9.js'; | ||
| import '../chunks/plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| import '../chunks/rpc.DZEh5xnQ.js'; | ||
| import 'pathe'; | ||
| import '../chunks/coverage.BfSEMtie.js'; | ||
| import '../chunks/coverage.BVb1JqW7.js'; | ||
| import '../chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import '../chunks/rpc.iNjF664v.js'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/source-map.DZdIqpIJ.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '../chunks/index.D6NDM5O1.js'; | ||
| import '../chunks/artifact.BNnEI1sJ.js'; | ||
| import '@vitest/utils/error'; | ||
| import '@vitest/utils/helpers'; | ||
| import '../chunks/utils.DYj33du9.js'; | ||
| import '../chunks/setup-common.vxjAyUtK.js'; | ||
| import '../chunks/plugins.CsoX-42X.js'; | ||
| import '../chunks/index.DzTmMrSM.js'; | ||
| import '../chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import '../chunks/index.CLtI1k_4.js'; | ||
| import '../chunks/artifact.DC5WoEgy.js'; | ||
| import '../chunks/display.CYwyMF4S.js'; | ||
| import '../task-utils.js'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/source-map'; | ||
| import '@vitest/utils/offset'; | ||
| import '../chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '@vitest/utils/diff'; | ||
| import 'tinyrainbow'; | ||
| import '../chunks/offset.Dy-5Fdfn.js'; | ||
| import 'tinybench'; | ||
| import 'expect-type'; | ||
| import '../chunks/init.DTAQFCjl.js'; | ||
| import '../chunks/init.CfiYZpFg.js'; | ||
| import 'node:fs'; | ||
| import 'node:module'; | ||
| import 'node:url'; | ||
| import '../chunks/index.DNRmy2jU.js'; | ||
| import '../chunks/index.DxR-nMjO.js'; | ||
| import '../chunks/modules.BJuCwlRJ.js'; | ||
@@ -44,15 +40,7 @@ import '../path.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; | ||
| import '../chunks/inspector.CvyFGlXm.js'; | ||
| import '../chunks/nativeModuleRunner.WlMdOB52.js'; | ||
| import '../chunks/index.CesbTg1C.js'; | ||
| import 'node:process'; | ||
| import 'node:fs/promises'; | ||
| import 'node:assert'; | ||
| import 'node:v8'; | ||
| import 'node:util'; | ||
| import 'node:perf_hooks'; | ||
| import 'node:timers'; | ||
| import 'node:timers/promises'; | ||
| import '@vitest/utils/constants'; | ||
| import 'node:util'; | ||
@@ -59,0 +47,0 @@ workerInit({ |
@@ -6,29 +6,24 @@ import { createRequire } from 'node:module'; | ||
| import util from 'node:util'; | ||
| import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants'; | ||
| import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks } from '../chunks/index.B4UTDegh.js'; | ||
| import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from '../chunks/setup-common.ZNdeu5wa.js'; | ||
| import { i as index, g as globalExpect } from '../chunks/index.D6NDM5O1.js'; | ||
| import { K as KNOWN_ASSET_TYPES } from '../chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import { s as setupChaiConfig, r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks } from '../chunks/index.JaztIWgW.js'; | ||
| import { s as startCoverageInsideWorker, a as stopCoverageInsideWorker } from '../chunks/coverage.BfSEMtie.js'; | ||
| import { i as index, g as globalExpect } from '../chunks/index.CLtI1k_4.js'; | ||
| import { c as closeInspector } from '../chunks/inspector.CvyFGlXm.js'; | ||
| import { s as startTests, p as publicCollect } from '../chunks/artifact.BNnEI1sJ.js'; | ||
| import { s as startTests, p as publicCollect } from '../chunks/artifact.DC5WoEgy.js'; | ||
| import { s as setupCommonEnv } from '../chunks/setup-common.vxjAyUtK.js'; | ||
| import { g as getWorkerState } from '../chunks/utils.DYj33du9.js'; | ||
| import 'chai'; | ||
| import 'node:async_hooks'; | ||
| import '../chunks/rpc.DZEh5xnQ.js'; | ||
| import 'pathe'; | ||
| import '../chunks/rpc.iNjF664v.js'; | ||
| import 'vite/module-runner'; | ||
| import '@vitest/utils/timers'; | ||
| import '../chunks/source-map.DZdIqpIJ.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '../chunks/coverage.CTzCuANN.js'; | ||
| import '../chunks/plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| import '@vitest/spy'; | ||
| import '@vitest/utils/helpers'; | ||
| import '@vitest/utils/offset'; | ||
| import '@vitest/utils/source-map'; | ||
| import '../chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/diff'; | ||
| import 'tinyrainbow'; | ||
| import '@vitest/utils/error'; | ||
| import '../chunks/coverage.BVb1JqW7.js'; | ||
| import '../chunks/spy.B8mHA9qu.js'; | ||
| import '../chunks/display.CYwyMF4S.js'; | ||
| import '../chunks/index.DzTmMrSM.js'; | ||
| import '../chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import '../task-utils.js'; | ||
| import '../chunks/plugins.CsoX-42X.js'; | ||
| import '../chunks/offset.Dy-5Fdfn.js'; | ||
| import 'tinybench'; | ||
@@ -35,0 +30,0 @@ import 'expect-type'; |
+21
-33
@@ -1,36 +0,32 @@ | ||
| import { s as setupBaseEnvironment, r as runBaseTests } from '../chunks/base.BKfXyFN7.js'; | ||
| import { w as workerInit } from '../chunks/init-threads.DLtIP5Qq.js'; | ||
| import { s as setupBaseEnvironment, r as runBaseTests } from '../chunks/base.B0fUxpj9.js'; | ||
| import { w as workerInit } from '../chunks/init-threads.Ch-Bw5j3.js'; | ||
| import 'node:vm'; | ||
| import '@vitest/spy'; | ||
| import '../chunks/index.B4UTDegh.js'; | ||
| import '../chunks/spy.B8mHA9qu.js'; | ||
| import '../chunks/index.JaztIWgW.js'; | ||
| import 'chai'; | ||
| import 'node:async_hooks'; | ||
| import '../chunks/setup-common.ZNdeu5wa.js'; | ||
| import '../chunks/coverage.CTzCuANN.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '../chunks/utils.DYj33du9.js'; | ||
| import '../chunks/plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| import '../chunks/rpc.DZEh5xnQ.js'; | ||
| import 'pathe'; | ||
| import '../chunks/coverage.BfSEMtie.js'; | ||
| import '../chunks/coverage.BVb1JqW7.js'; | ||
| import '../chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import '../chunks/rpc.iNjF664v.js'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/source-map.DZdIqpIJ.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '../chunks/index.D6NDM5O1.js'; | ||
| import '../chunks/artifact.BNnEI1sJ.js'; | ||
| import '@vitest/utils/error'; | ||
| import '@vitest/utils/helpers'; | ||
| import '../chunks/utils.DYj33du9.js'; | ||
| import '../chunks/setup-common.vxjAyUtK.js'; | ||
| import '../chunks/plugins.CsoX-42X.js'; | ||
| import '../chunks/index.DzTmMrSM.js'; | ||
| import '../chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import '../chunks/index.CLtI1k_4.js'; | ||
| import '../chunks/artifact.DC5WoEgy.js'; | ||
| import '../chunks/display.CYwyMF4S.js'; | ||
| import '../task-utils.js'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/source-map'; | ||
| import '@vitest/utils/offset'; | ||
| import '../chunks/_commonjsHelpers.D26ty3Ew.js'; | ||
| import '@vitest/utils/diff'; | ||
| import 'tinyrainbow'; | ||
| import '../chunks/offset.Dy-5Fdfn.js'; | ||
| import 'tinybench'; | ||
| import 'expect-type'; | ||
| import '../chunks/init.DTAQFCjl.js'; | ||
| import '../chunks/init.CfiYZpFg.js'; | ||
| import 'node:fs'; | ||
| import 'node:module'; | ||
| import 'node:url'; | ||
| import '../chunks/index.DNRmy2jU.js'; | ||
| import '../chunks/index.DxR-nMjO.js'; | ||
| import '../chunks/modules.BJuCwlRJ.js'; | ||
@@ -44,15 +40,7 @@ import '../path.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; | ||
| import '../chunks/inspector.CvyFGlXm.js'; | ||
| import '../chunks/nativeModuleRunner.WlMdOB52.js'; | ||
| import '../chunks/index.CesbTg1C.js'; | ||
| import 'node:process'; | ||
| import 'node:fs/promises'; | ||
| import 'node:assert'; | ||
| import 'node:v8'; | ||
| import 'node:util'; | ||
| import 'node:perf_hooks'; | ||
| import 'node:timers'; | ||
| import 'node:timers/promises'; | ||
| import '@vitest/utils/constants'; | ||
| import 'node:util'; | ||
| import 'node:worker_threads'; | ||
@@ -59,0 +47,0 @@ |
+13
-15
@@ -1,11 +0,10 @@ | ||
| import { w as workerInit } from '../chunks/init-forks.BG4bCDny.js'; | ||
| import { r as runVmTests, s as setupVmWorker } from '../chunks/vm.CeHWcIrU.js'; | ||
| import '../chunks/init.DTAQFCjl.js'; | ||
| import { w as workerInit } from '../chunks/init-forks.CXzT841o.js'; | ||
| import { r as runVmTests, s as setupVmWorker } from '../chunks/vm.DoQh8CN9.js'; | ||
| import '../chunks/init.CfiYZpFg.js'; | ||
| import 'node:fs'; | ||
| import 'node:module'; | ||
| import 'node:url'; | ||
| import 'pathe'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/index.DNRmy2jU.js'; | ||
| import '@vitest/utils/helpers'; | ||
| import '../chunks/index.DxR-nMjO.js'; | ||
| import '../chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import '../chunks/modules.BJuCwlRJ.js'; | ||
@@ -21,14 +20,13 @@ import '../chunks/utils.DYj33du9.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/error'; | ||
| import 'tinyrainbow'; | ||
| import '../chunks/rpc.DZEh5xnQ.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '../chunks/source-map.DZdIqpIJ.js'; | ||
| import '../chunks/index.DzTmMrSM.js'; | ||
| import '../chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import '../chunks/rpc.iNjF664v.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '@vitest/utils/source-map'; | ||
| import '../chunks/inspector.CvyFGlXm.js'; | ||
| import '../chunks/console.DjVIMaXT.js'; | ||
| import '../chunks/console.omGxyKMT.js'; | ||
| import 'node:stream'; | ||
| import '@vitest/utils/resolver'; | ||
| import '@vitest/utils/constants'; | ||
| import '../chunks/resolver.CERfsKE-.js'; | ||
| import '../chunks/setup-common.vxjAyUtK.js'; | ||
| import '../chunks/plugins.CsoX-42X.js'; | ||
@@ -35,0 +33,0 @@ workerInit({ |
@@ -1,12 +0,11 @@ | ||
| import { w as workerInit } from '../chunks/init-threads.DLtIP5Qq.js'; | ||
| import { s as setupVmWorker, r as runVmTests } from '../chunks/vm.CeHWcIrU.js'; | ||
| import { w as workerInit } from '../chunks/init-threads.Ch-Bw5j3.js'; | ||
| import { s as setupVmWorker, r as runVmTests } from '../chunks/vm.DoQh8CN9.js'; | ||
| import 'node:worker_threads'; | ||
| import '../chunks/init.DTAQFCjl.js'; | ||
| import '../chunks/init.CfiYZpFg.js'; | ||
| import 'node:fs'; | ||
| import 'node:module'; | ||
| import 'node:url'; | ||
| import 'pathe'; | ||
| import 'vite/module-runner'; | ||
| import '../chunks/index.DNRmy2jU.js'; | ||
| import '@vitest/utils/helpers'; | ||
| import '../chunks/index.DxR-nMjO.js'; | ||
| import '../chunks/pathe.M-eThtNZ.CbK_Vbae.js'; | ||
| import '../chunks/modules.BJuCwlRJ.js'; | ||
@@ -22,14 +21,13 @@ import '../chunks/utils.DYj33du9.js'; | ||
| import 'node:console'; | ||
| import '@vitest/utils/serialize'; | ||
| import '@vitest/utils/error'; | ||
| import 'tinyrainbow'; | ||
| import '../chunks/rpc.DZEh5xnQ.js'; | ||
| import '@vitest/utils/timers'; | ||
| import '../chunks/source-map.DZdIqpIJ.js'; | ||
| import '../chunks/index.DzTmMrSM.js'; | ||
| import '../chunks/tinyrainbow.Ht9iggcq.js'; | ||
| import '../chunks/rpc.iNjF664v.js'; | ||
| import '../chunks/index.Chj8NDwU.js'; | ||
| import '@vitest/utils/source-map'; | ||
| import '../chunks/inspector.CvyFGlXm.js'; | ||
| import '../chunks/console.DjVIMaXT.js'; | ||
| import '../chunks/console.omGxyKMT.js'; | ||
| import 'node:stream'; | ||
| import '@vitest/utils/resolver'; | ||
| import '@vitest/utils/constants'; | ||
| import '../chunks/resolver.CERfsKE-.js'; | ||
| import '../chunks/setup-common.vxjAyUtK.js'; | ||
| import '../chunks/plugins.CsoX-42X.js'; | ||
@@ -36,0 +34,0 @@ workerInit({ |
+165
-1
@@ -319,2 +319,61 @@ # Vitest core license | ||
| ## convert-source-map | ||
| License: MIT | ||
| By: Thorsten Lorenz | ||
| Repository: git://github.com/thlorenz/convert-source-map.git | ||
| > Copyright 2013 Thorsten Lorenz. | ||
| > All rights reserved. | ||
| > | ||
| > Permission is hereby granted, free of charge, to any person | ||
| > obtaining a copy of this software and associated documentation | ||
| > files (the "Software"), to deal in the Software without | ||
| > restriction, including without limitation the rights to use, | ||
| > copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| > copies of the Software, and to permit persons to whom the | ||
| > Software is furnished to do so, subject to the following | ||
| > conditions: | ||
| > | ||
| > The above copyright notice and this permission notice shall be | ||
| > included in all copies or substantial portions of the Software. | ||
| > | ||
| > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
| > OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| > NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
| > HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
| > WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| > OTHER DEALINGS IN THE SOFTWARE. | ||
| --------------------------------------- | ||
| ## diff-sequences | ||
| License: MIT | ||
| Repository: https://github.com/jestjs/jest.git | ||
| > MIT License | ||
| > | ||
| > Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| > | ||
| > Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| > of this software and associated documentation files (the "Software"), to deal | ||
| > in the Software without restriction, including without limitation the rights | ||
| > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| > copies of the Software, and to permit persons to whom the Software is | ||
| > furnished to do so, subject to the following conditions: | ||
| > | ||
| > The above copyright notice and this permission notice shall be included in all | ||
| > copies or substantial portions of the Software. | ||
| > | ||
| > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| > SOFTWARE. | ||
| --------------------------------------- | ||
| ## flatted | ||
@@ -350,3 +409,3 @@ License: ISC | ||
| > | ||
| > Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Simon Lydell | ||
| > Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024 Simon Lydell | ||
| > | ||
@@ -524,2 +583,79 @@ > Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| ## pathe | ||
| License: MIT | ||
| Repository: unjs/pathe | ||
| > MIT License | ||
| > | ||
| > Copyright (c) Pooya Parsa <pooya@pi0.io> - Daniel Roe <daniel@roe.dev> | ||
| > | ||
| > Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| > of this software and associated documentation files (the "Software"), to deal | ||
| > in the Software without restriction, including without limitation the rights | ||
| > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| > copies of the Software, and to permit persons to whom the Software is | ||
| > furnished to do so, subject to the following conditions: | ||
| > | ||
| > The above copyright notice and this permission notice shall be included in all | ||
| > copies or substantial portions of the Software. | ||
| > | ||
| > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| > SOFTWARE. | ||
| > | ||
| > --- | ||
| > | ||
| > Copyright Joyent, Inc. and other Node contributors. | ||
| > | ||
| > Permission is hereby granted, free of charge, to any person obtaining a | ||
| > copy of this software and associated documentation files (the | ||
| > "Software"), to deal in the Software without restriction, including | ||
| > without limitation the rights to use, copy, modify, merge, publish, | ||
| > distribute, sublicense, and/or sell copies of the Software, and to permit | ||
| > persons to whom the Software is furnished to do so, subject to the | ||
| > following conditions: | ||
| > | ||
| > The above copyright notice and this permission notice shall be included | ||
| > in all copies or substantial portions of the Software. | ||
| > | ||
| > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| > OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN | ||
| > NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
| > DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
| > OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
| > USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| > | ||
| > --- | ||
| > | ||
| > Bundled zeptomatch (https://github.com/fabiospampinato/zeptomatch) | ||
| > | ||
| > The MIT License (MIT) | ||
| > | ||
| > Copyright (c) 2023-present Fabio Spampinato | ||
| > | ||
| > Permission is hereby granted, free of charge, to any person obtaining a | ||
| > copy of this software and associated documentation files (the "Software"), | ||
| > to deal in the Software without restriction, including without limitation | ||
| > the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| > and/or sell copies of the Software, and to permit persons to whom the | ||
| > Software is furnished to do so, subject to the following conditions: | ||
| > | ||
| > The above copyright notice and this permission notice shall be included in | ||
| > all copies or substantial portions of the Software. | ||
| > | ||
| > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| > DEALINGS IN THE SOFTWARE. | ||
| --------------------------------------- | ||
| ## prompts | ||
@@ -725,2 +861,30 @@ License: MIT | ||
| ## tinyrainbow | ||
| License: MIT | ||
| Repository: git+https://github.com/tinylibs/tinyrainbow.git | ||
| > MIT License | ||
| > | ||
| > Copyright (c) 2022 Tinylibs | ||
| > | ||
| > Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| > of this software and associated documentation files (the "Software"), to deal | ||
| > in the Software without restriction, including without limitation the rights | ||
| > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| > copies of the Software, and to permit persons to whom the Software is | ||
| > furnished to do so, subject to the following conditions: | ||
| > | ||
| > The above copyright notice and this permission notice shall be included in all | ||
| > copies or substantial portions of the Software. | ||
| > | ||
| > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| > SOFTWARE. | ||
| --------------------------------------- | ||
| ## type-detect | ||
@@ -727,0 +891,0 @@ License: MIT |
+15
-15
| { | ||
| "name": "vitest", | ||
| "type": "module", | ||
| "version": "5.0.0-beta.6", | ||
| "version": "5.0.0-beta.7", | ||
| "description": "Next generation testing framework powered by Vite", | ||
@@ -121,7 +121,7 @@ "author": "Anthony Fu <anthonyfu117@hotmail.com>", | ||
| "vite": "^6.4.0 || ^7.0.0 || ^8.0.0", | ||
| "@vitest/browser-preview": "5.0.0-beta.6", | ||
| "@vitest/browser-playwright": "5.0.0-beta.6", | ||
| "@vitest/coverage-istanbul": "5.0.0-beta.6", | ||
| "@vitest/ui": "5.0.0-beta.6", | ||
| "@vitest/coverage-v8": "5.0.0-beta.6" | ||
| "@vitest/browser-playwright": "5.0.0-beta.7", | ||
| "@vitest/browser-preview": "5.0.0-beta.7", | ||
| "@vitest/coverage-v8": "5.0.0-beta.7", | ||
| "@vitest/coverage-istanbul": "5.0.0-beta.7", | ||
| "@vitest/ui": "5.0.0-beta.7" | ||
| }, | ||
@@ -171,5 +171,4 @@ "peerDependenciesMeta": { | ||
| "expect-type": "^1.3.0", | ||
| "magic-string": "^0.30.21", | ||
| "magic-string": "^1.0.0", | ||
| "obug": "^2.1.1", | ||
| "pathe": "^2.0.3", | ||
| "picomatch": "^4.0.3", | ||
@@ -180,8 +179,4 @@ "std-env": "^4.0.0-rc.1", | ||
| "tinyglobby": "^0.2.15", | ||
| "tinyrainbow": "^3.1.0", | ||
| "why-is-node-running": "^2.3.0", | ||
| "@vitest/mocker": "5.0.0-beta.6", | ||
| "@vitest/utils": "5.0.0-beta.6", | ||
| "@vitest/pretty-format": "5.0.0-beta.6", | ||
| "@vitest/spy": "5.0.0-beta.6" | ||
| "@vitest/mocker": "5.0.0-beta.7" | ||
| }, | ||
@@ -211,9 +206,14 @@ "devDependencies": { | ||
| "mime": "^4.1.0", | ||
| "pathe": "^2.0.3", | ||
| "prompts": "^2.4.2", | ||
| "strip-literal": "^3.1.0", | ||
| "tinyhighlight": "^0.3.2", | ||
| "tinyrainbow": "^3.1.0", | ||
| "vite": "^6.4.0 || ^7.0.0 || ^8.0.0", | ||
| "ws": "^8.20.1", | ||
| "@vitest/expect": "5.0.0-beta.6", | ||
| "@vitest/snapshot": "5.0.0-beta.6" | ||
| "@vitest/expect": "5.0.0-beta.7", | ||
| "@vitest/snapshot": "5.0.0-beta.7", | ||
| "@vitest/pretty-format": "5.0.0-beta.7", | ||
| "@vitest/spy": "5.0.0-beta.7", | ||
| "@vitest/utils": "5.0.0-beta.7" | ||
| }, | ||
@@ -220,0 +220,0 @@ "scripts": { |
| var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {}; | ||
| function getDefaultExportFromCjs(x) { | ||
| return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x; | ||
| } | ||
| export { commonjsGlobal as c, getDefaultExportFromCjs as g }; |
Sorry, the diff of this file is too big to display
| import { runInThisContext } from 'node:vm'; | ||
| import * as spyModule from '@vitest/spy'; | ||
| import { r as resolveTestRunner, a as resolveSnapshotEnvironment, d as detectAsyncLeaks, s as setupChaiConfig } from './index.B4UTDegh.js'; | ||
| import { l as loadEnvironment, e as emitModuleRunner, a as listenForErrors } from './init.DTAQFCjl.js'; | ||
| import { N as NativeModuleRunner } from './nativeModuleRunner.WlMdOB52.js'; | ||
| import { Traces } from '../traces.js'; | ||
| import { V as VitestEvaluatedModules } from './rpc.DZEh5xnQ.js'; | ||
| import { s as startVitestModuleRunner, c as createNodeImportMeta } from './index.DNRmy2jU.js'; | ||
| import { performance as performance$1 } from 'node:perf_hooks'; | ||
| import { s as setupCommonEnv, b as startCoverageInsideWorker, c as stopCoverageInsideWorker } from './setup-common.ZNdeu5wa.js'; | ||
| import { i as index, g as globalExpect, v as vi } from './index.D6NDM5O1.js'; | ||
| import { c as closeInspector } from './inspector.CvyFGlXm.js'; | ||
| import { s as startTests, p as publicCollect } from './artifact.BNnEI1sJ.js'; | ||
| import { createRequire } from 'node:module'; | ||
| import timers from 'node:timers'; | ||
| import timersPromises from 'node:timers/promises'; | ||
| import util from 'node:util'; | ||
| import { KNOWN_ASSET_TYPES } from '@vitest/utils/constants'; | ||
| import { g as getWorkerState, r as resetModules, p as provideWorkerState, a as getSafeWorkerState } from './utils.DYj33du9.js'; | ||
| // this should only be used in Node | ||
| let globalSetup = false; | ||
| async function setupGlobalEnv(config, environment) { | ||
| await setupCommonEnv(config); | ||
| Object.defineProperty(globalThis, "__vitest_index__", { | ||
| value: index, | ||
| enumerable: false | ||
| }); | ||
| globalExpect.setState({ environment: environment.name }); | ||
| if (globalSetup) return; | ||
| globalSetup = true; | ||
| if ((environment.viteEnvironment || environment.name) === "client") { | ||
| const _require = createRequire(import.meta.url); | ||
| // always mock "required" `css` files, because we cannot process them | ||
| _require.extensions[".css"] = resolveCss; | ||
| _require.extensions[".scss"] = resolveCss; | ||
| _require.extensions[".sass"] = resolveCss; | ||
| _require.extensions[".less"] = resolveCss; | ||
| // since we are using Vite, we can assume how these will be resolved | ||
| KNOWN_ASSET_TYPES.forEach((type) => { | ||
| _require.extensions[`.${type}`] = resolveAsset; | ||
| }); | ||
| process.env.SSR = ""; | ||
| } else process.env.SSR = "1"; | ||
| // @ts-expect-error not typed global for patched timers | ||
| globalThis.__vitest_required__ = { | ||
| util, | ||
| timers, | ||
| timersPromises | ||
| }; | ||
| if (!config.disableConsoleIntercept) await setupConsoleLogSpy(); | ||
| } | ||
| function resolveCss(mod) { | ||
| mod.exports = ""; | ||
| } | ||
| function resolveAsset(mod, url) { | ||
| mod.exports = url; | ||
| } | ||
| async function setupConsoleLogSpy() { | ||
| const { createCustomConsole } = await import('./console.DjVIMaXT.js'); | ||
| globalThis.console = createCustomConsole(); | ||
| } | ||
| // browser shouldn't call this! | ||
| async function run(method, files, config, moduleRunner, environment, traces) { | ||
| const workerState = getWorkerState(); | ||
| const [testRunner] = await Promise.all([ | ||
| traces.$("vitest.runtime.runner", () => resolveTestRunner(config, moduleRunner, traces)), | ||
| traces.$("vitest.runtime.global_env", () => setupGlobalEnv(config, environment)), | ||
| traces.$("vitest.runtime.coverage.start", () => startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })), | ||
| traces.$("vitest.runtime.snapshot.environment", async () => { | ||
| if (!workerState.config.snapshotOptions.snapshotEnvironment) workerState.config.snapshotOptions.snapshotEnvironment = await resolveSnapshotEnvironment(config, moduleRunner); | ||
| }) | ||
| ]); | ||
| workerState.onCancel((reason) => { | ||
| closeInspector(config); | ||
| testRunner.cancel?.(reason); | ||
| }); | ||
| workerState.durations.prepare = performance$1.now() - workerState.durations.prepare; | ||
| await traces.$(`vitest.test.runner.${method}`, async () => { | ||
| for (const file of files) { | ||
| if (config.isolate) { | ||
| moduleRunner.mocker?.reset(); | ||
| resetModules(workerState.evaluatedModules, true); | ||
| } | ||
| workerState.filepath = file.filepath; | ||
| if (method === "run") { | ||
| const collectAsyncLeaks = config.detectAsyncLeaks ? detectAsyncLeaks(file.filepath, workerState.ctx.projectName) : void 0; | ||
| await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => startTests([file], testRunner)); | ||
| const leaks = await collectAsyncLeaks?.(); | ||
| if (leaks?.length) workerState.rpc.onAsyncLeaks(leaks); | ||
| } else await traces.$(`vitest.test.runner.${method}.module`, { attributes: { "code.file.path": file.filepath } }, () => publicCollect([file], testRunner)); | ||
| // reset after tests, because user might call `vi.setConfig` in setupFile | ||
| vi.resetConfig(); | ||
| // mocks should not affect different files | ||
| vi.restoreAllMocks(); | ||
| } | ||
| }); | ||
| await traces.$("vitest.runtime.coverage.stop", () => stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.isolate })); | ||
| } | ||
| let _moduleRunner; | ||
| const evaluatedModules = new VitestEvaluatedModules(); | ||
| const moduleExecutionInfo = /* @__PURE__ */ new Map(); | ||
| async function startModuleRunner(options) { | ||
| if (_moduleRunner) return _moduleRunner; | ||
| process.exit = (code = process.exitCode || 0) => { | ||
| throw new Error(`process.exit unexpectedly called with "${code}"`); | ||
| }; | ||
| const state = () => getSafeWorkerState() || options.state; | ||
| listenForErrors(state); | ||
| if (options.state.config.experimental.viteModuleRunner === false) { | ||
| const root = options.state.config.root; | ||
| let mocker; | ||
| if (options.state.config.experimental.nodeLoader !== false) { | ||
| // this additionally imports acorn/magic-string | ||
| const { NativeModuleMocker } = await import('./nativeModuleMocker.BKtCThoO.js'); | ||
| mocker = new NativeModuleMocker({ | ||
| async resolveId(id, importer) { | ||
| // TODO: use import.meta.resolve instead | ||
| return state().rpc.resolve(id, importer, "__vitest__"); | ||
| }, | ||
| root, | ||
| moduleDirectories: state().config.deps.moduleDirectories || ["/node_modules/"], | ||
| traces: options.traces || new Traces({ enabled: false }), | ||
| getCurrentTestFilepath() { | ||
| return state().filepath; | ||
| }, | ||
| spyModule | ||
| }); | ||
| } | ||
| _moduleRunner = new NativeModuleRunner(root, mocker); | ||
| return _moduleRunner; | ||
| } | ||
| _moduleRunner = startVitestModuleRunner(options); | ||
| return _moduleRunner; | ||
| } | ||
| let _currentEnvironment; | ||
| let _environmentTime; | ||
| /** @experimental */ | ||
| async function setupBaseEnvironment(context) { | ||
| if (context.config.experimental.viteModuleRunner === false) { | ||
| const { setupNodeLoaderHooks } = await import('./native.DPzPHdi5.js'); | ||
| await setupNodeLoaderHooks(context); | ||
| } | ||
| const startTime = performance.now(); | ||
| const { environment: { name: environmentName, options: environmentOptions }, rpc, config } = context; | ||
| // we could load @vite/env, but it would take ~8ms, while this takes ~0,02ms | ||
| if (context.config.serializedDefines) try { | ||
| runInThisContext(`(() =>{\n${context.config.serializedDefines}})()`, { | ||
| lineOffset: 1, | ||
| filename: "virtual:load-defines.js" | ||
| }); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom "defines": ${error.message}`); | ||
| } | ||
| const otel = context.traces; | ||
| const { environment, loader } = await loadEnvironment(environmentName, config.root, rpc, otel, context.config.experimental.viteModuleRunner); | ||
| _currentEnvironment = environment; | ||
| const env = await otel.$("vitest.runtime.environment.setup", { attributes: { | ||
| "vitest.environment": environment.name, | ||
| "vitest.environment.vite_environment": environment.viteEnvironment || environment.name | ||
| } }, () => environment.setup(globalThis, environmentOptions || config.environmentOptions || {})); | ||
| _environmentTime = performance.now() - startTime; | ||
| if (config.chaiConfig) setupChaiConfig(config.chaiConfig); | ||
| return async () => { | ||
| await otel.$("vitest.runtime.environment.teardown", () => env.teardown(globalThis)); | ||
| await loader?.close(); | ||
| }; | ||
| } | ||
| /** @experimental */ | ||
| async function runBaseTests(method, state, traces) { | ||
| const { ctx } = state; | ||
| state.environment = _currentEnvironment; | ||
| state.durations.environment = _environmentTime; | ||
| // state has new context, but we want to reuse existing ones | ||
| state.evaluatedModules = evaluatedModules; | ||
| state.moduleExecutionInfo = moduleExecutionInfo; | ||
| provideWorkerState(globalThis, state); | ||
| if (ctx.invalidates) ctx.invalidates.forEach((filepath) => { | ||
| (state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => { | ||
| state.evaluatedModules.invalidateModule(module); | ||
| }); | ||
| }); | ||
| ctx.files.forEach((i) => { | ||
| const filepath = i.filepath; | ||
| (state.evaluatedModules.fileToModulesMap.get(filepath) || []).forEach((module) => { | ||
| state.evaluatedModules.invalidateModule(module); | ||
| }); | ||
| }); | ||
| const moduleRunner = await startModuleRunner({ | ||
| state, | ||
| evaluatedModules: state.evaluatedModules, | ||
| spyModule, | ||
| createImportMeta: createNodeImportMeta, | ||
| traces | ||
| }); | ||
| emitModuleRunner(moduleRunner); | ||
| await run(method, ctx.files, ctx.config, moduleRunner, _currentEnvironment, traces); | ||
| } | ||
| export { runBaseTests as r, setupBaseEnvironment as s }; |
| import { aH as FileSpecification } from './config.d.CKWK3nld.js'; | ||
| import { O as OTELCarrier } from './rpc.d.C6-dGZ2f.js'; | ||
| import { T as TestExecutionMethod } from './worker.d.JES7ffPK.js'; | ||
| type SerializedTestSpecification = [project: { | ||
| name: string | undefined; | ||
| root: string; | ||
| }, file: string, options: { | ||
| pool: string; | ||
| testLines?: number[] | undefined; | ||
| testIds?: string[] | undefined; | ||
| testNamePattern?: RegExp | undefined; | ||
| testTagsFilter?: string[] | undefined; | ||
| }]; | ||
| interface ModuleDefinitionLocation { | ||
| line: number; | ||
| column: number; | ||
| } | ||
| interface SourceModuleLocations { | ||
| modules: ModuleDefinitionDiagnostic[]; | ||
| untracked: ModuleDefinitionDiagnostic[]; | ||
| } | ||
| interface ModuleDefinitionDiagnostic { | ||
| start: ModuleDefinitionLocation; | ||
| end: ModuleDefinitionLocation; | ||
| startIndex: number; | ||
| endIndex: number; | ||
| rawUrl: string; | ||
| resolvedUrl: string; | ||
| resolvedId: string; | ||
| } | ||
| interface ModuleDefinitionDurationsDiagnostic extends ModuleDefinitionDiagnostic { | ||
| selfTime: number; | ||
| totalTime: number; | ||
| transformTime?: number; | ||
| external?: boolean; | ||
| importer?: string; | ||
| } | ||
| interface UntrackedModuleDefinitionDiagnostic { | ||
| url: string; | ||
| resolvedId: string; | ||
| resolvedUrl: string; | ||
| selfTime: number; | ||
| totalTime: number; | ||
| transformTime?: number; | ||
| external?: boolean; | ||
| importer?: string; | ||
| } | ||
| interface SourceModuleDiagnostic { | ||
| modules: ModuleDefinitionDurationsDiagnostic[]; | ||
| untrackedModules: UntrackedModuleDefinitionDiagnostic[]; | ||
| } | ||
| interface BrowserTesterOptions { | ||
| method: TestExecutionMethod; | ||
| files: FileSpecification[]; | ||
| providedContext: string; | ||
| otelCarrier?: OTELCarrier; | ||
| concurrencyId: number; | ||
| workerId: number; | ||
| } | ||
| export type { BrowserTesterOptions as B, ModuleDefinitionDurationsDiagnostic as M, SerializedTestSpecification as S, UntrackedModuleDefinitionDiagnostic as U, ModuleDefinitionDiagnostic as a, ModuleDefinitionLocation as b, SourceModuleDiagnostic as c, SourceModuleLocations as d }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| import { Console } from 'node:console'; | ||
| import { relative } from 'node:path'; | ||
| import { Writable } from 'node:stream'; | ||
| import { getSafeTimers } from '@vitest/utils/timers'; | ||
| import c from 'tinyrainbow'; | ||
| import { R as RealDate } from './rpc.DZEh5xnQ.js'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import 'pathe'; | ||
| import 'vite/module-runner'; | ||
| import './index.Chj8NDwU.js'; | ||
| const UNKNOWN_TEST_ID = "__vitest__unknown_test__"; | ||
| function getTaskIdByStack(root) { | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE_ERROR")).stack?.split("\n"); | ||
| if (!stack) return UNKNOWN_TEST_ID; | ||
| const index = stack.findIndex((line) => line.includes("at Console.value")); | ||
| const line = index === -1 ? null : stack[index + 2]; | ||
| if (!line) return UNKNOWN_TEST_ID; | ||
| const filepath = line.match(/at\s(.*)\s?/)?.[1]; | ||
| if (filepath) return relative(root, filepath); | ||
| return UNKNOWN_TEST_ID; | ||
| } | ||
| function createCustomConsole(defaultState) { | ||
| const stdoutBuffer = /* @__PURE__ */ new Map(); | ||
| const stderrBuffer = /* @__PURE__ */ new Map(); | ||
| const timers = /* @__PURE__ */ new Map(); | ||
| const { queueMicrotask } = getSafeTimers(); | ||
| function queueCancelableMicrotask(callback) { | ||
| let canceled = false; | ||
| queueMicrotask(() => { | ||
| if (!canceled) callback(); | ||
| }); | ||
| return () => { | ||
| canceled = true; | ||
| }; | ||
| } | ||
| const state = () => defaultState || getWorkerState(); | ||
| // group sync console.log calls with micro task | ||
| function schedule(taskId) { | ||
| const timer = timers.get(taskId); | ||
| const { stdoutTime, stderrTime } = timer; | ||
| timer.cancel?.(); | ||
| timer.cancel = queueCancelableMicrotask(() => { | ||
| if (stderrTime < stdoutTime) { | ||
| sendStderr(taskId); | ||
| sendStdout(taskId); | ||
| } else { | ||
| sendStdout(taskId); | ||
| sendStderr(taskId); | ||
| } | ||
| }); | ||
| } | ||
| function sendStdout(taskId) { | ||
| sendBuffer("stdout", taskId); | ||
| } | ||
| function sendStderr(taskId) { | ||
| sendBuffer("stderr", taskId); | ||
| } | ||
| function sendBuffer(type, taskId) { | ||
| const buffers = type === "stdout" ? stdoutBuffer : stderrBuffer; | ||
| const buffer = buffers.get(taskId); | ||
| if (!buffer) return; | ||
| if (state().config.printConsoleTrace) buffer.forEach(([buffer, origin]) => { | ||
| sendLog(type, taskId, String(buffer), buffer.length, origin); | ||
| }); | ||
| else sendLog(type, taskId, buffer.map((i) => String(i[0])).join(""), buffer.length); | ||
| const timer = timers.get(taskId); | ||
| buffers.delete(taskId); | ||
| if (type === "stderr") timer.stderrTime = 0; | ||
| else timer.stdoutTime = 0; | ||
| } | ||
| function sendLog(type, taskId, content, size, origin) { | ||
| const timer = timers.get(taskId); | ||
| const time = type === "stderr" ? timer.stderrTime : timer.stdoutTime; | ||
| state().rpc.onUserConsoleLog({ | ||
| type, | ||
| content: content || "<empty line>", | ||
| taskId, | ||
| time: time || RealDate.now(), | ||
| size, | ||
| origin | ||
| }); | ||
| } | ||
| return new Console({ | ||
| stdout: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stdoutTime = timer.stdoutTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stdoutTime: RealDate.now(), | ||
| stderrTime: 0 | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stdoutBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stdoutBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const trace = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n").slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| stderr: new Writable({ write(data, encoding, callback) { | ||
| const s = state(); | ||
| const id = s?.current?.id || s?.current?.suite?.id || s.current?.file.id || getTaskIdByStack(s.config.root); | ||
| let timer = timers.get(id); | ||
| if (timer) timer.stderrTime = timer.stderrTime || RealDate.now(); | ||
| else { | ||
| timer = { | ||
| stderrTime: RealDate.now(), | ||
| stdoutTime: 0 | ||
| }; | ||
| timers.set(id, timer); | ||
| } | ||
| let buffer = stderrBuffer.get(id); | ||
| if (!buffer) { | ||
| buffer = []; | ||
| stderrBuffer.set(id, buffer); | ||
| } | ||
| if (state().config.printConsoleTrace) { | ||
| const limit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = limit + 6; | ||
| const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack?.split("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| if (stack?.some((line) => line.includes("at Console.trace"))) buffer.push([data, void 0]); | ||
| else { | ||
| const trace = stack?.slice(7).join("\n"); | ||
| Error.stackTraceLimit = limit; | ||
| buffer.push([data, trace]); | ||
| } | ||
| } else buffer.push([data, void 0]); | ||
| schedule(id); | ||
| callback(); | ||
| } }), | ||
| colorMode: c.isColorSupported, | ||
| groupIndentation: 2 | ||
| }); | ||
| } | ||
| export { UNKNOWN_TEST_ID, createCustomConsole }; |
| const CoverageProviderMap = { | ||
| v8: "@vitest/coverage-v8", | ||
| istanbul: "@vitest/coverage-istanbul" | ||
| }; | ||
| async function resolveCoverageProviderModule(options, loader) { | ||
| if (!options?.enabled || !options.provider) return null; | ||
| const provider = options.provider; | ||
| if (provider === "v8" || provider === "istanbul") { | ||
| let builtInModule = CoverageProviderMap[provider]; | ||
| if (provider === "v8" && loader.isBrowser) builtInModule += "/browser"; | ||
| const { default: coverageModule } = loader.isBrowser ? await loader.import(builtInModule) : await import( | ||
| /* @vite-ignore */ | ||
| builtInModule | ||
| ); | ||
| if (!coverageModule) throw new Error(`Failed to load ${CoverageProviderMap[provider]}. Default export is missing.`); | ||
| return coverageModule; | ||
| } | ||
| let customProviderModule; | ||
| try { | ||
| customProviderModule = await loader.import(options.customProviderModule); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom CoverageProviderModule from ${options.customProviderModule}`, { cause: error }); | ||
| } | ||
| if (customProviderModule.default == null) throw new Error(`Custom CoverageProviderModule loaded from ${options.customProviderModule} was not the default export`); | ||
| return customProviderModule.default; | ||
| } | ||
| export { CoverageProviderMap as C, resolveCoverageProviderModule as r }; |
| import './config.d.CKWK3nld.js'; | ||
| interface RuntimeCoverageModuleLoader { | ||
| import: (id: string) => Promise<{ | ||
| default: RuntimeCoverageProviderModule; | ||
| }>; | ||
| isBrowser?: boolean; | ||
| moduleExecutionInfo?: Map<string, { | ||
| startOffset: number; | ||
| }>; | ||
| } | ||
| interface RuntimeCoverageProviderModule { | ||
| /** | ||
| * Factory for creating a new coverage provider | ||
| */ | ||
| getProvider: () => any; | ||
| /** | ||
| * Executed before tests are run in the worker thread. | ||
| */ | ||
| startCoverage?: (runtimeOptions: { | ||
| isolate: boolean; | ||
| /** @internal */ | ||
| autoAttachSubprocess: boolean; | ||
| /** @internal */ | ||
| reportsDirectory: string; | ||
| }) => unknown | Promise<unknown>; | ||
| /** | ||
| * Executed on after each run in the worker thread. Possible to return a payload passed to the provider | ||
| */ | ||
| takeCoverage?: (runtimeOptions?: { | ||
| moduleExecutionInfo?: Map<string, { | ||
| startOffset: number; | ||
| }>; | ||
| }) => unknown | Promise<unknown>; | ||
| /** | ||
| * Executed after all tests have been run in the worker thread. | ||
| */ | ||
| stopCoverage?: (runtimeOptions: { | ||
| isolate: boolean; | ||
| }) => unknown | Promise<unknown>; | ||
| } | ||
| export type { RuntimeCoverageModuleLoader as R, RuntimeCoverageProviderModule as a }; |
| import { existsSync, writeFileSync, readFileSync } from 'node:fs'; | ||
| import { mkdir, writeFile } from 'node:fs/promises'; | ||
| import { resolve, dirname, relative } from 'node:path'; | ||
| import { detectPackageManager, installPackage } from './index.CMESou6r.js'; | ||
| import { p as prompt, f as findConfigFile } from './index.Djaij2xr.js'; | ||
| import { x } from 'tinyexec'; | ||
| import c from 'tinyrainbow'; | ||
| import 'node:process'; | ||
| import 'node:url'; | ||
| import '@vitest/utils/helpers'; | ||
| import './index.CesbTg1C.js'; | ||
| import 'node:module'; | ||
| import 'pathe'; | ||
| import 'node:assert'; | ||
| import 'node:v8'; | ||
| import 'node:util'; | ||
| import 'tinyglobby'; | ||
| import 'vite'; | ||
| import './constants.-juJ8b_4.js'; | ||
| import './defaults.B_pFOTYy.js'; | ||
| import 'node:os'; | ||
| import './env.BKKtU2WC.js'; | ||
| import 'std-env'; | ||
| import './utils.DKODp04v.js'; | ||
| import '@vitest/utils/display'; | ||
| import 'node:crypto'; | ||
| import './_commonjsHelpers.D26ty3Ew.js'; | ||
| import 'readline'; | ||
| import 'events'; | ||
| const jsxExample = { | ||
| name: "HelloWorld.jsx", | ||
| js: ` | ||
| export default function HelloWorld({ name }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| ts: ` | ||
| export default function HelloWorld({ name }: { name: string }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from '@testing-library/jsx' | ||
| import HelloWorld from './HelloWorld.<EXT>x' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(<HelloWorld name="Vitest" />) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const vueExample = { | ||
| name: "HelloWorld.vue", | ||
| js: ` | ||
| <script setup> | ||
| defineProps({ | ||
| name: String | ||
| }) | ||
| <\/script> | ||
| <template> | ||
| <div> | ||
| <h1>Hello {{ name }}!</h1> | ||
| </div> | ||
| </template> | ||
| `, | ||
| ts: ` | ||
| <script setup lang="ts"> | ||
| defineProps<{ | ||
| name: string | ||
| }>() | ||
| <\/script> | ||
| <template> | ||
| <div> | ||
| <h1>Hello {{ name }}!</h1> | ||
| </div> | ||
| </template> | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-vue' | ||
| import HelloWorld from './HelloWorld.vue' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(HelloWorld, { | ||
| props: { name: 'Vitest' }, | ||
| }) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const svelteExample = { | ||
| name: "HelloWorld.svelte", | ||
| js: ` | ||
| <script> | ||
| export let name | ||
| <\/script> | ||
| <h1>Hello {name}!</h1> | ||
| `, | ||
| ts: ` | ||
| <script lang="ts"> | ||
| export let name: string | ||
| <\/script> | ||
| <h1>Hello {name}!</h1> | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-svelte' | ||
| import HelloWorld from './HelloWorld.svelte' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(HelloWorld, { name: 'Vitest' }) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const markoExample = { | ||
| name: "HelloWorld.marko", | ||
| js: ` | ||
| class { | ||
| onCreate() { | ||
| this.state = { name: null } | ||
| } | ||
| } | ||
| <h1>Hello \${state.name}!</h1> | ||
| `, | ||
| ts: ` | ||
| export interface Input { | ||
| name: string | ||
| } | ||
| <h1>Hello \${input.name}!</h1> | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from '@marko/testing-library' | ||
| import HelloWorld from './HelloWorld.svelte' | ||
| test('renders name', async () => { | ||
| const { getByText } = await render(HelloWorld, { name: 'Vitest' }) | ||
| const element = getByText('Hello Vitest!') | ||
| expect(element).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const litExample = { | ||
| name: "HelloWorld.js", | ||
| js: ` | ||
| import { html, LitElement } from 'lit' | ||
| export class HelloWorld extends LitElement { | ||
| static properties = { | ||
| name: { type: String }, | ||
| } | ||
| constructor() { | ||
| super() | ||
| this.name = 'World' | ||
| } | ||
| render() { | ||
| return html\`<h1>Hello \${this.name}!</h1>\` | ||
| } | ||
| } | ||
| customElements.define('hello-world', HelloWorld) | ||
| `, | ||
| ts: ` | ||
| import { html, LitElement } from 'lit' | ||
| import { customElement, property } from 'lit/decorators.js' | ||
| @customElement('hello-world') | ||
| export class HelloWorld extends LitElement { | ||
| @property({ type: String }) | ||
| name = 'World' | ||
| render() { | ||
| return html\`<h1>Hello \${this.name}!</h1>\` | ||
| } | ||
| } | ||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| 'hello-world': HelloWorld | ||
| } | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-lit' | ||
| import { html } from 'lit' | ||
| import './HelloWorld.js' | ||
| test('renders name', async () => { | ||
| const screen = render(html\`<hello-world name="Vitest"></hello-world>\`) | ||
| const element = screen.getByText('Hello Vitest!') | ||
| await expect.element(element).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const qwikExample = { | ||
| name: "HelloWorld.jsx", | ||
| js: ` | ||
| import { component$ } from '@builder.io/qwik' | ||
| export default component$(({ name }) => { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| }) | ||
| `, | ||
| ts: ` | ||
| import { component$ } from '@builder.io/qwik' | ||
| export default component$(({ name }: { name: string }) => { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| }) | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-qwik' | ||
| import HelloWorld from './HelloWorld.tsx' | ||
| test('renders name', async () => { | ||
| const { getByText } = render(<HelloWorld name="Vitest" />) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const preactExample = { | ||
| name: "HelloWorld.jsx", | ||
| js: ` | ||
| export default function HelloWorld({ name }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| ts: ` | ||
| export default function HelloWorld({ name }: { name: string }) { | ||
| return ( | ||
| <div> | ||
| <h1>Hello {name}!</h1> | ||
| </div> | ||
| ) | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { render } from 'vitest-browser-preact' | ||
| import HelloWorld from './HelloWorld.<EXT>x' | ||
| test('renders name', async () => { | ||
| const { getByText } = render(<HelloWorld name="Vitest" />) | ||
| await expect.element(getByText('Hello Vitest!')).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| const vanillaExample = { | ||
| name: "HelloWorld.js", | ||
| js: ` | ||
| export default function HelloWorld({ name }) { | ||
| const parent = document.createElement('div') | ||
| const h1 = document.createElement('h1') | ||
| h1.textContent = 'Hello ' + name + '!' | ||
| parent.appendChild(h1) | ||
| return parent | ||
| } | ||
| `, | ||
| ts: ` | ||
| export default function HelloWorld({ name }: { name: string }): HTMLDivElement { | ||
| const parent = document.createElement('div') | ||
| const h1 = document.createElement('h1') | ||
| h1.textContent = 'Hello ' + name + '!' | ||
| parent.appendChild(h1) | ||
| return parent | ||
| } | ||
| `, | ||
| test: ` | ||
| import { expect, test } from 'vitest' | ||
| import { getByText } from '@testing-library/dom' | ||
| import HelloWorld from './HelloWorld.js' | ||
| test('renders name', () => { | ||
| const parent = HelloWorld({ name: 'Vitest' }) | ||
| document.body.appendChild(parent) | ||
| const element = getByText(parent, 'Hello Vitest!') | ||
| expect(element).toBeInTheDocument() | ||
| }) | ||
| ` | ||
| }; | ||
| function getExampleTest(framework) { | ||
| switch (framework) { | ||
| case "solid": return { | ||
| ...jsxExample, | ||
| test: jsxExample.test.replace("@testing-library/jsx", `@testing-library/${framework}`) | ||
| }; | ||
| case "preact": return preactExample; | ||
| case "react": return { | ||
| ...jsxExample, | ||
| test: jsxExample.test.replace("@testing-library/jsx", `vitest-browser-${framework}`) | ||
| }; | ||
| case "vue": return vueExample; | ||
| case "svelte": return svelteExample; | ||
| case "lit": return litExample; | ||
| case "marko": return markoExample; | ||
| case "qwik": return qwikExample; | ||
| default: return vanillaExample; | ||
| } | ||
| } | ||
| async function generateExampleFiles(framework, lang) { | ||
| const example = getExampleTest(framework); | ||
| let fileName = example.name; | ||
| const folder = resolve(process.cwd(), "vitest-example"); | ||
| const fileContent = example[lang]; | ||
| if (!existsSync(folder)) await mkdir(folder, { recursive: true }); | ||
| const isJSX = fileName.endsWith(".jsx"); | ||
| if (isJSX && lang === "ts") fileName = fileName.replace(".jsx", ".tsx"); | ||
| else if (fileName.endsWith(".js") && lang === "ts") fileName = fileName.replace(".js", ".ts"); | ||
| example.test = example.test.replace("<EXT>", lang); | ||
| const filePath = resolve(folder, fileName); | ||
| const testPath = resolve(folder, `HelloWorld.test.${isJSX ? `${lang}x` : lang}`); | ||
| writeFileSync(filePath, fileContent.trimStart(), "utf-8"); | ||
| writeFileSync(testPath, example.test.trimStart(), "utf-8"); | ||
| return testPath; | ||
| } | ||
| // eslint-disable-next-line no-console | ||
| const log = console.log; | ||
| function getProviderOptions() { | ||
| return Object.entries({ | ||
| playwright: "Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev", | ||
| webdriverio: "WebdriverIO uses WebDriver protocol. Read more: https://webdriver.io", | ||
| preview: "Preview is useful to quickly run your tests in the browser, but not suitable for CI." | ||
| }).map(([provider, description]) => { | ||
| return { | ||
| title: provider, | ||
| description, | ||
| value: provider | ||
| }; | ||
| }); | ||
| } | ||
| function getBrowserNames(provider) { | ||
| switch (provider) { | ||
| case "webdriverio": return [ | ||
| "chrome", | ||
| "firefox", | ||
| "edge", | ||
| "safari" | ||
| ]; | ||
| case "playwright": return [ | ||
| "chromium", | ||
| "firefox", | ||
| "webkit" | ||
| ]; | ||
| case "preview": return [ | ||
| "chrome", | ||
| "firefox", | ||
| "safari" | ||
| ]; | ||
| } | ||
| } | ||
| function getFramework() { | ||
| return [ | ||
| { | ||
| title: "vanilla", | ||
| value: "vanilla", | ||
| description: "No framework, just plain JavaScript or TypeScript." | ||
| }, | ||
| { | ||
| title: "vue", | ||
| value: "vue", | ||
| description: "\"The Progressive JavaScript Framework\"" | ||
| }, | ||
| { | ||
| title: "svelte", | ||
| value: "svelte", | ||
| description: "\"Svelte: cybernetically enhanced web apps\"" | ||
| }, | ||
| { | ||
| title: "react", | ||
| value: "react", | ||
| description: "\"The library for web and native user interfaces\"" | ||
| }, | ||
| { | ||
| title: "lit", | ||
| value: "lit", | ||
| description: "\"A simple library for building fast, lightweight web components.\"" | ||
| }, | ||
| { | ||
| title: "preact", | ||
| value: "preact", | ||
| description: "\"Fast 3kB alternative to React with the same modern API\"" | ||
| }, | ||
| { | ||
| title: "solid", | ||
| value: "solid", | ||
| description: "\"Simple and performant reactivity for building user interfaces\"" | ||
| }, | ||
| { | ||
| title: "marko", | ||
| value: "marko", | ||
| description: "\"A declarative, HTML-based language that makes building web apps fun\"" | ||
| }, | ||
| { | ||
| title: "qwik", | ||
| value: "qwik", | ||
| description: "\"Instantly interactive web apps at scale\"" | ||
| } | ||
| ]; | ||
| } | ||
| function getFrameworkTestPackage(framework) { | ||
| switch (framework) { | ||
| case "vanilla": return null; | ||
| case "vue": return "vitest-browser-vue"; | ||
| case "svelte": return "vitest-browser-svelte"; | ||
| case "react": return "vitest-browser-react"; | ||
| case "lit": return "vitest-browser-lit"; | ||
| case "preact": return "vitest-browser-preact"; | ||
| case "solid": return "@solidjs/testing-library"; | ||
| case "marko": return "@marko/testing-library"; | ||
| case "qwik": return "vitest-browser-qwik"; | ||
| } | ||
| throw new Error(`Unsupported framework: ${framework}`); | ||
| } | ||
| function getFrameworkPluginPackage(framework) { | ||
| switch (framework) { | ||
| case "vue": return "@vitejs/plugin-vue"; | ||
| case "svelte": return "@sveltejs/vite-plugin-svelte"; | ||
| case "react": return "@vitejs/plugin-react"; | ||
| case "preact": return "@preact/preset-vite"; | ||
| case "solid": return "vite-plugin-solid"; | ||
| case "marko": return "@marko/vite"; | ||
| case "qwik": return "@builder.io/qwik/optimizer"; | ||
| } | ||
| return null; | ||
| } | ||
| function getLanguageOptions() { | ||
| return [{ | ||
| title: "TypeScript", | ||
| description: "Use TypeScript.", | ||
| value: "ts" | ||
| }, { | ||
| title: "JavaScript", | ||
| description: "Use plain JavaScript.", | ||
| value: "js" | ||
| }]; | ||
| } | ||
| async function installPackages(pkgManager, packages) { | ||
| if (!packages.length) { | ||
| log(c.green("✔"), c.bold("All packages are already installed.")); | ||
| return; | ||
| } | ||
| log(c.cyan("◼"), c.bold("Installing packages...")); | ||
| log(c.cyan("◼"), packages.join(", ")); | ||
| log(); | ||
| await installPackage(packages, { | ||
| dev: true, | ||
| packageManager: pkgManager ?? void 0 | ||
| }); | ||
| } | ||
| function readPkgJson(path) { | ||
| if (!existsSync(path)) return null; | ||
| const content = readFileSync(path, "utf-8"); | ||
| return JSON.parse(content); | ||
| } | ||
| function getPossibleDefaults(dependencies) { | ||
| return { | ||
| lang: "ts", | ||
| provider: getPossibleProvider(dependencies), | ||
| framework: getPossibleFramework(dependencies) | ||
| }; | ||
| } | ||
| function getPossibleFramework(dependencies) { | ||
| if (dependencies.vue || dependencies["vue-tsc"] || dependencies["@vue/reactivity"]) return "vue"; | ||
| if (dependencies.react || dependencies["react-dom"]) return "react"; | ||
| if (dependencies.svelte || dependencies["@sveltejs/kit"]) return "svelte"; | ||
| if (dependencies.lit || dependencies["lit-html"]) return "lit"; | ||
| if (dependencies.preact) return "preact"; | ||
| if (dependencies["solid-js"] || dependencies["@solidjs/start"]) return "solid"; | ||
| if (dependencies.marko) return "marko"; | ||
| if (dependencies["@builder.io/qwik"] || dependencies["@qwik.dev/core"]) return "qwik"; | ||
| return "vanilla"; | ||
| } | ||
| function getPossibleProvider(dependencies) { | ||
| if (dependencies.webdriverio || dependencies["@wdio/cli"] || dependencies["@wdio/config"]) return "webdriverio"; | ||
| // playwright is the default recommendation | ||
| return "playwright"; | ||
| } | ||
| function getProviderDocsLink(provider) { | ||
| switch (provider) { | ||
| case "playwright": return "https://vitest.dev/config/browser/playwright"; | ||
| case "webdriverio": return "https://vitest.dev/config/browser/webdriverio"; | ||
| } | ||
| } | ||
| function sort(choices, value) { | ||
| const index = choices.findIndex((i) => i.value === value); | ||
| if (index === -1) return choices; | ||
| return [choices.splice(index, 1)[0], ...choices]; | ||
| } | ||
| function fail() { | ||
| process.exitCode = 1; | ||
| } | ||
| function getFrameworkImportInfo(framework) { | ||
| switch (framework) { | ||
| case "svelte": return { | ||
| importName: "svelte", | ||
| isNamedExport: true | ||
| }; | ||
| case "qwik": return { | ||
| importName: "qwikVite", | ||
| isNamedExport: true | ||
| }; | ||
| default: return { | ||
| importName: framework, | ||
| isNamedExport: false | ||
| }; | ||
| } | ||
| } | ||
| async function generateFrameworkConfigFile(options) { | ||
| const { importName, isNamedExport } = getFrameworkImportInfo(options.framework); | ||
| const frameworkImport = isNamedExport ? `import { ${importName} } from '${options.frameworkPlugin}'` : `import ${importName} from '${options.frameworkPlugin}'`; | ||
| const configContent = [ | ||
| `import { defineConfig } from 'vitest/config'`, | ||
| `import { ${options.provider} } from '@vitest/browser-${options.provider}'`, | ||
| options.frameworkPlugin ? frameworkImport : null, | ||
| ``, | ||
| "export default defineConfig({", | ||
| options.frameworkPlugin ? ` plugins: [${importName}()],` : null, | ||
| ` test: {`, | ||
| ` browser: {`, | ||
| ` enabled: true,`, | ||
| ` provider: ${options.provider}(),`, | ||
| options.provider !== "preview" && ` // ${getProviderDocsLink(options.provider)}`, | ||
| ` instances: [`, | ||
| ...options.browsers.map((browser) => ` { browser: '${browser}' },`), | ||
| ` ],`, | ||
| ` },`, | ||
| ` },`, | ||
| `})`, | ||
| "" | ||
| ].filter((t) => typeof t === "string").join("\n"); | ||
| await writeFile(options.configPath, configContent); | ||
| } | ||
| async function updatePkgJsonScripts(pkgJsonPath, vitestScript) { | ||
| if (!existsSync(pkgJsonPath)) { | ||
| const pkg = { scripts: { "test:browser": vitestScript } }; | ||
| await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8"); | ||
| } else { | ||
| const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8")); | ||
| pkg.scripts = pkg.scripts || {}; | ||
| pkg.scripts["test:browser"] = vitestScript; | ||
| await writeFile(pkgJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8"); | ||
| } | ||
| log(c.green("✔"), "Added \"test:browser\" script to your package.json."); | ||
| } | ||
| function getRunScript(pkgManager) { | ||
| switch (pkgManager) { | ||
| case "yarn@berry": | ||
| case "yarn": return "yarn test:browser"; | ||
| case "pnpm@6": | ||
| case "pnpm": return "pnpm test:browser"; | ||
| case "bun": return "bun test:browser"; | ||
| default: return "npm run test:browser"; | ||
| } | ||
| } | ||
| function getPlaywrightRunArgs(pkgManager) { | ||
| switch (pkgManager) { | ||
| case "yarn@berry": | ||
| case "yarn": return ["yarn", "exec"]; | ||
| case "pnpm@6": | ||
| case "pnpm": return ["pnpx"]; | ||
| case "bun": return ["bunx"]; | ||
| default: return ["npx"]; | ||
| } | ||
| } | ||
| async function create() { | ||
| log(c.cyan("◼"), "This utility will help you set up a browser testing environment.\n"); | ||
| const pkgJsonPath = resolve(process.cwd(), "package.json"); | ||
| const pkg = readPkgJson(pkgJsonPath) || {}; | ||
| const dependencies = { | ||
| ...pkg.dependencies, | ||
| ...pkg.devDependencies | ||
| }; | ||
| const defaults = getPossibleDefaults(dependencies); | ||
| const { lang } = await prompt({ | ||
| type: "select", | ||
| name: "lang", | ||
| message: "Choose a language for your tests", | ||
| choices: sort(getLanguageOptions(), defaults?.lang) | ||
| }); | ||
| if (!lang) return fail(); | ||
| const { provider } = await prompt({ | ||
| type: "select", | ||
| name: "provider", | ||
| message: "Choose a browser provider. Vitest will use its API to control the testing environment", | ||
| choices: sort(getProviderOptions(), defaults?.provider) | ||
| }); | ||
| if (!provider) return fail(); | ||
| const { browsers } = await prompt({ | ||
| type: "multiselect", | ||
| name: "browsers", | ||
| message: "Choose a browser", | ||
| choices: getBrowserNames(provider).map((browser) => ({ | ||
| title: browser, | ||
| value: browser | ||
| })) | ||
| }); | ||
| if (!provider) return fail(); | ||
| const { framework } = await prompt({ | ||
| type: "select", | ||
| name: "framework", | ||
| message: "Choose your framework", | ||
| choices: sort(getFramework(), defaults?.framework) | ||
| }); | ||
| if (!framework) return fail(); | ||
| let installPlaywright = false; | ||
| if (provider === "playwright") ({installPlaywright} = await prompt({ | ||
| type: "confirm", | ||
| name: "installPlaywright", | ||
| message: `Install Playwright browsers (can be done manually via 'pnpm exec playwright install')?` | ||
| })); | ||
| if (installPlaywright == null) return fail(); | ||
| const dependenciesToInstall = [`@vitest/browser-${provider}`]; | ||
| const frameworkPackage = getFrameworkTestPackage(framework); | ||
| if (frameworkPackage) dependenciesToInstall.push(frameworkPackage); | ||
| const frameworkPlugin = getFrameworkPluginPackage(framework); | ||
| if (frameworkPlugin) dependenciesToInstall.push(frameworkPlugin); | ||
| const pkgManager = await detectPackageManager(); | ||
| log(); | ||
| await installPackages(pkgManager, dependenciesToInstall.filter((pkg) => !dependencies[pkg])); | ||
| const rootConfig = findConfigFile(process.cwd()); | ||
| let scriptCommand = "vitest"; | ||
| log(); | ||
| if (rootConfig) { | ||
| const configPath = resolve(dirname(rootConfig), `vitest.browser.config.${lang}`); | ||
| scriptCommand = `vitest --config=${relative(process.cwd(), configPath)}`; | ||
| await generateFrameworkConfigFile({ | ||
| configPath, | ||
| framework, | ||
| frameworkPlugin, | ||
| provider, | ||
| browsers | ||
| }); | ||
| log( | ||
| c.green("✔"), | ||
| "Created a new config file for browser tests:", | ||
| c.bold(relative(process.cwd(), configPath)), | ||
| // TODO: Can we modify the config ourselves? | ||
| "\nSince you already have a Vitest config file, it is recommended to copy the contents of the new file ", | ||
| "into your existing config located at ", | ||
| c.bold(relative(process.cwd(), rootConfig)) | ||
| ); | ||
| } else { | ||
| const configPath = resolve(process.cwd(), `vitest.config.${lang}`); | ||
| await generateFrameworkConfigFile({ | ||
| configPath, | ||
| framework, | ||
| frameworkPlugin, | ||
| provider, | ||
| browsers | ||
| }); | ||
| log(c.green("✔"), "Created a config file for browser tests:", c.bold(relative(process.cwd(), configPath))); | ||
| } | ||
| log(); | ||
| await updatePkgJsonScripts(pkgJsonPath, scriptCommand); | ||
| if (installPlaywright) { | ||
| log(); | ||
| const [command, ...args] = getPlaywrightRunArgs(pkgManager); | ||
| const allArgs = [ | ||
| ...args, | ||
| "playwright", | ||
| "install", | ||
| "--with-deps" | ||
| ]; | ||
| log(c.cyan("◼"), `Installing Playwright dependencies with \`${c.bold(command)} ${c.bold(allArgs.join(" "))}\`...`); | ||
| log(); | ||
| await x(command, allArgs, { nodeOptions: { stdio: [ | ||
| "pipe", | ||
| "inherit", | ||
| "inherit" | ||
| ] } }); | ||
| } | ||
| log(); | ||
| const exampleTestFile = await generateExampleFiles(framework, lang); | ||
| log(c.green("✔"), "Created example test file in", c.bold(relative(process.cwd(), exampleTestFile))); | ||
| log(c.dim(" You can safely delete this file once you have written your own tests.")); | ||
| log(); | ||
| log(c.cyan("◼"), "All done! Run your tests with", c.bold(getRunScript(pkgManager))); | ||
| } | ||
| export { create }; |
| import nodeos__default from 'node:os'; | ||
| import './env.BKKtU2WC.js'; | ||
| import { isCI, isAgent } from 'std-env'; | ||
| const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"]; | ||
| const defaultExclude = ["**/node_modules/**", "**/.git/**"]; | ||
| const benchmarkConfigDefaults = { | ||
| enabled: false, | ||
| include: ["**/*.{bench,benchmark}.?(c|m)[jt]s?(x)"], | ||
| exclude: defaultExclude, | ||
| includeSource: [], | ||
| retainSamples: false, | ||
| suppressExportGetterWarnings: false, | ||
| projectName: "" | ||
| }; | ||
| // These are the generic defaults for coverage. Providers may also set some provider specific defaults. | ||
| const coverageConfigDefaults = { | ||
| provider: "v8", | ||
| enabled: false, | ||
| clean: true, | ||
| cleanOnRerun: true, | ||
| reportsDirectory: "./coverage", | ||
| exclude: [], | ||
| reportOnFailure: false, | ||
| reporter: [ | ||
| "text", | ||
| "html", | ||
| "clover", | ||
| "json" | ||
| ], | ||
| allowExternal: false, | ||
| excludeAfterRemap: false, | ||
| processingConcurrency: Math.min(20, nodeos__default.availableParallelism?.() ?? nodeos__default.cpus().length), | ||
| ignoreClassMethods: [], | ||
| skipFull: false, | ||
| watermarks: { | ||
| statements: [50, 80], | ||
| functions: [50, 80], | ||
| branches: [50, 80], | ||
| lines: [50, 80] | ||
| }, | ||
| autoAttachSubprocess: false | ||
| }; | ||
| const fakeTimersDefaults = { | ||
| loopLimit: 1e4, | ||
| shouldClearNativeTimers: true | ||
| }; | ||
| const configDefaults = Object.freeze({ | ||
| allowOnly: !isCI, | ||
| isolate: true, | ||
| watch: !isCI && process.stdin.isTTY && !isAgent, | ||
| globals: false, | ||
| environment: "node", | ||
| clearMocks: true, | ||
| restoreMocks: false, | ||
| mockReset: false, | ||
| unstubGlobals: false, | ||
| unstubEnvs: false, | ||
| include: defaultInclude, | ||
| exclude: defaultExclude, | ||
| teardownTimeout: 1e4, | ||
| forceRerunTriggers: ["**/package.json", "**/{vitest,vite}.config.*"], | ||
| update: false, | ||
| reporters: [isAgent ? "minimal" : "default", ...process.env.GITHUB_ACTIONS === "true" ? ["github-actions"] : []], | ||
| silent: false, | ||
| hideSkippedTests: false, | ||
| api: false, | ||
| ui: false, | ||
| uiBase: "/__vitest__/", | ||
| open: !isCI, | ||
| css: { include: [] }, | ||
| coverage: coverageConfigDefaults, | ||
| fakeTimers: fakeTimersDefaults, | ||
| maxConcurrency: 5, | ||
| dangerouslyIgnoreUnhandledErrors: false, | ||
| typecheck: { | ||
| checker: "tsc", | ||
| include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"], | ||
| exclude: defaultExclude | ||
| }, | ||
| slowTestThreshold: 300, | ||
| taskTitleValueFormatTruncate: 40, | ||
| disableConsoleIntercept: false, | ||
| detectAsyncLeaks: false | ||
| }); | ||
| export { coverageConfigDefaults as a, defaultInclude as b, configDefaults as c, defaultExclude as d, benchmarkConfigDefaults as e }; |
| import { isCI } from 'std-env'; | ||
| const isNode = typeof process < "u" && typeof process.stdout < "u" && !process.versions?.deno && !globalThis.window; | ||
| const isDeno = typeof process < "u" && typeof process.stdout < "u" && process.versions?.deno !== void 0; | ||
| const isWindows = (isNode || isDeno) && process.platform === "win32"; | ||
| const isTTY = (isNode || isDeno) && process.stdout?.isTTY && !isCI; | ||
| const isForceColor = () => "FORCE_COLOR" in process.env; | ||
| export { isTTY as a, isWindows as b, isForceColor as i }; |
| import { Awaitable } from '@vitest/utils'; | ||
| interface EnvironmentReturn { | ||
| teardown: (global: any) => Awaitable<void>; | ||
| } | ||
| interface VmEnvironmentReturn { | ||
| getVmContext: () => { | ||
| [key: string]: any; | ||
| }; | ||
| teardown: () => Awaitable<void>; | ||
| } | ||
| interface Environment { | ||
| name: string; | ||
| /** | ||
| * @deprecated use `viteEnvironment` instead. Uses `name` by default | ||
| */ | ||
| transformMode?: "web" | "ssr"; | ||
| /** | ||
| * Environment initiated by the Vite server. It is usually available | ||
| * as `vite.server.environments.${name}`. | ||
| * | ||
| * By default, fallbacks to `name`. | ||
| */ | ||
| viteEnvironment?: "client" | "ssr" | ({} & string); | ||
| setupVM?: (options: Record<string, any>) => Awaitable<VmEnvironmentReturn>; | ||
| setup: (global: any, options: Record<string, any>) => Awaitable<EnvironmentReturn>; | ||
| } | ||
| export type { Environment as E, VmEnvironmentReturn as V, EnvironmentReturn as a }; |
| import { g as globalApis } from './constants.-juJ8b_4.js'; | ||
| import { i as index } from './index.D6NDM5O1.js'; | ||
| import './artifact.BNnEI1sJ.js'; | ||
| import '@vitest/utils/error'; | ||
| import '@vitest/utils/helpers'; | ||
| import '@vitest/utils/timers'; | ||
| import '../task-utils.js'; | ||
| import 'pathe'; | ||
| import '@vitest/utils/display'; | ||
| import '@vitest/utils/source-map'; | ||
| import './utils.DYj33du9.js'; | ||
| import '@vitest/spy'; | ||
| import '@vitest/utils/offset'; | ||
| import './_commonjsHelpers.D26ty3Ew.js'; | ||
| import './rpc.DZEh5xnQ.js'; | ||
| import 'vite/module-runner'; | ||
| import './index.Chj8NDwU.js'; | ||
| import '@vitest/utils/diff'; | ||
| import 'tinyrainbow'; | ||
| import 'chai'; | ||
| import './plugins.DrsmdUE2.js'; | ||
| import '@vitest/pretty-format'; | ||
| import 'tinybench'; | ||
| import 'expect-type'; | ||
| function registerApiGlobally() { | ||
| globalApis.forEach((api) => { | ||
| // @ts-expect-error I know what I am doing :P | ||
| globalThis[api] = index[api]; | ||
| }); | ||
| } | ||
| export { registerApiGlobally }; |
| import * as chai from 'chai'; | ||
| import { createHook } from 'node:async_hooks'; | ||
| import { l as loadDiffConfig, a as loadSnapshotSerializers, t as takeCoverageInsideWorker } from './setup-common.ZNdeu5wa.js'; | ||
| import { r as rpc } from './rpc.DZEh5xnQ.js'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import { T as TestRunner } from './index.D6NDM5O1.js'; | ||
| function setupChaiConfig(config) { | ||
| Object.assign(chai.config, config); | ||
| } | ||
| async function resolveSnapshotEnvironment(config, moduleRunner) { | ||
| if (!config.snapshotEnvironment) { | ||
| const { VitestNodeSnapshotEnvironment } = await import('./node.C9I1sbE9.js'); | ||
| return new VitestNodeSnapshotEnvironment(); | ||
| } | ||
| const mod = await moduleRunner.import(config.snapshotEnvironment); | ||
| if (typeof mod.default !== "object" || !mod.default) throw new Error("Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`"); | ||
| return mod.default; | ||
| } | ||
| const IGNORED_TYPES = new Set([ | ||
| "DNSCHANNEL", | ||
| "ELDHISTOGRAM", | ||
| "PerformanceObserver", | ||
| "RANDOMBYTESREQUEST", | ||
| "SIGNREQUEST", | ||
| "STREAM_END_OF_STREAM", | ||
| "TCPWRAP", | ||
| "TIMERWRAP", | ||
| "TLSWRAP", | ||
| "ZLIB" | ||
| ]); | ||
| function detectAsyncLeaks(testFile, projectName) { | ||
| const resources = /* @__PURE__ */ new Map(); | ||
| const hook = createHook({ | ||
| init(asyncId, type, triggerAsyncId, resource) { | ||
| if (IGNORED_TYPES.has(type)) return; | ||
| let stack = ""; | ||
| const limit = Error.stackTraceLimit; | ||
| // VitestModuleEvaluator's async wrapper of node:vm causes out-of-bound stack traces, simply skip it. | ||
| // Crash fixed in https://github.com/vitejs/vite/pull/21585 | ||
| try { | ||
| Error.stackTraceLimit = 100; | ||
| stack = (/* @__PURE__ */ new Error("VITEST_DETECT_ASYNC_LEAKS")).stack || ""; | ||
| } catch { | ||
| return; | ||
| } finally { | ||
| Error.stackTraceLimit = limit; | ||
| } | ||
| if (!stack.includes(testFile)) { | ||
| const trigger = resources.get(triggerAsyncId); | ||
| if (!trigger) return; | ||
| stack = trigger.stack; | ||
| } | ||
| let isActive = isActiveDefault; | ||
| if ("hasRef" in resource) { | ||
| const ref = new WeakRef(resource); | ||
| isActive = () => ref.deref()?.hasRef() ?? false; | ||
| } | ||
| resources.set(asyncId, { | ||
| type, | ||
| stack, | ||
| projectName, | ||
| filename: testFile, | ||
| isActive | ||
| }); | ||
| }, | ||
| destroy(asyncId) { | ||
| if (resources.get(asyncId)?.type !== "PROMISE") resources.delete(asyncId); | ||
| }, | ||
| promiseResolve(asyncId) { | ||
| resources.delete(asyncId); | ||
| } | ||
| }); | ||
| hook.enable(); | ||
| return async function collect() { | ||
| await new Promise((resolve) => setImmediate(resolve)); | ||
| hook.disable(); | ||
| const leaks = []; | ||
| for (const resource of resources.values()) if (resource.isActive()) leaks.push({ | ||
| stack: resource.stack, | ||
| type: resource.type, | ||
| filename: resource.filename, | ||
| projectName: resource.projectName | ||
| }); | ||
| resources.clear(); | ||
| return leaks; | ||
| }; | ||
| } | ||
| function isActiveDefault() { | ||
| return true; | ||
| } | ||
| async function getTestRunnerConstructor(config, moduleRunner) { | ||
| if (!config.runner) return TestRunner; | ||
| const mod = await moduleRunner.import(config.runner); | ||
| if (!mod.default && typeof mod.default !== "function") throw new Error(`Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}`); | ||
| return mod.default; | ||
| } | ||
| async function resolveTestRunner(config, moduleRunner, traces) { | ||
| const testRunner = new (await (getTestRunnerConstructor(config, moduleRunner)))(config); | ||
| // inject private executor to every runner | ||
| Object.defineProperty(testRunner, "moduleRunner", { | ||
| value: moduleRunner, | ||
| enumerable: false, | ||
| configurable: false | ||
| }); | ||
| if (!testRunner.config) testRunner.config = config; | ||
| if (!testRunner.importFile) throw new Error("Runner must implement \"importFile\" method."); | ||
| if ("__setTraces" in testRunner) testRunner.__setTraces(traces); | ||
| const [diffOptions] = await Promise.all([loadDiffConfig(config, moduleRunner), loadSnapshotSerializers(config, moduleRunner)]); | ||
| testRunner.config._diffOptions = diffOptions; | ||
| // patch some methods, so custom runners don't need to call RPC | ||
| const originalOnTaskUpdate = testRunner.onTaskUpdate; | ||
| testRunner.onTaskUpdate = async (task, events) => { | ||
| const p = rpc().onTaskUpdate(task, events); | ||
| await originalOnTaskUpdate?.call(testRunner, task, events); | ||
| return p; | ||
| }; | ||
| // patch some methods, so custom runners don't need to call RPC | ||
| const originalOnTestAnnotate = testRunner.onTestAnnotate; | ||
| testRunner.onTestAnnotate = async (test, annotation) => { | ||
| const p = rpc().onTaskArtifactRecord(test.id, { | ||
| type: "internal:annotation", | ||
| location: annotation.location, | ||
| annotation | ||
| }); | ||
| const overriddenResult = await originalOnTestAnnotate?.call(testRunner, test, annotation); | ||
| const vitestResult = await p; | ||
| return overriddenResult || vitestResult.annotation; | ||
| }; | ||
| const originalOnTestArtifactRecord = testRunner.onTestArtifactRecord; | ||
| testRunner.onTestArtifactRecord = async (test, artifact) => { | ||
| const p = rpc().onTaskArtifactRecord(test.id, artifact); | ||
| const overriddenResult = await originalOnTestArtifactRecord?.call(testRunner, test, artifact); | ||
| const vitestResult = await p; | ||
| return overriddenResult || vitestResult; | ||
| }; | ||
| const originalOnCollectStart = testRunner.onCollectStart; | ||
| testRunner.onCollectStart = async (file) => { | ||
| await rpc().onQueued(file); | ||
| await originalOnCollectStart?.call(testRunner, file); | ||
| }; | ||
| const originalOnCollected = testRunner.onCollected; | ||
| testRunner.onCollected = async (files) => { | ||
| const state = getWorkerState(); | ||
| files.forEach((file) => { | ||
| file.prepareDuration = state.durations.prepare; | ||
| file.environmentLoad = state.durations.environment; | ||
| // should be collected only for a single test file in a batch | ||
| state.durations.prepare = 0; | ||
| state.durations.environment = 0; | ||
| }); | ||
| // Strip function conditions from retry config before sending via RPC | ||
| // Functions cannot be cloned by structured clone algorithm | ||
| const sanitizeRetryConditions = (task) => { | ||
| if (task.retry && typeof task.retry === "object" && typeof task.retry.condition === "function") | ||
| // Remove function condition - it can't be serialized | ||
| task.retry = { | ||
| ...task.retry, | ||
| condition: void 0 | ||
| }; | ||
| if (task.tasks) task.tasks.forEach(sanitizeRetryConditions); | ||
| }; | ||
| files.forEach(sanitizeRetryConditions); | ||
| rpc().onCollected(files); | ||
| await originalOnCollected?.call(testRunner, files); | ||
| }; | ||
| const originalOnAfterRun = testRunner.onAfterRunFiles; | ||
| testRunner.onAfterRunFiles = async (files) => { | ||
| const state = getWorkerState(); | ||
| const coverage = await takeCoverageInsideWorker(config.coverage, moduleRunner); | ||
| if (coverage) rpc().onAfterSuiteRun({ | ||
| coverage, | ||
| testFiles: files.map((file) => file.name).sort(), | ||
| environment: state.environment.viteEnvironment || state.environment.name, | ||
| projectName: state.ctx.projectName | ||
| }); | ||
| await originalOnAfterRun?.call(testRunner, files); | ||
| }; | ||
| const originalOnAfterRunTask = testRunner.onAfterRunTask; | ||
| testRunner.onAfterRunTask = async (test) => { | ||
| if (config.bail && test.result?.state === "fail") { | ||
| if (1 + await rpc().getCountOfFailedTests() >= config.bail) { | ||
| rpc().onCancel("test-failure"); | ||
| testRunner.cancel?.("test-failure"); | ||
| } | ||
| } | ||
| await originalOnAfterRunTask?.call(testRunner, test); | ||
| }; | ||
| return testRunner; | ||
| } | ||
| export { resolveSnapshotEnvironment as a, detectAsyncLeaks as d, resolveTestRunner as r, setupChaiConfig as s }; |
| import fs__default, { statSync, realpathSync } from 'node:fs'; | ||
| import { builtinModules, createRequire } from 'node:module'; | ||
| import path, { win32, dirname, join } from 'node:path'; | ||
| import process$1 from 'node:process'; | ||
| import fs from 'node:fs/promises'; | ||
| import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1, URL as URL$1 } from 'node:url'; | ||
| import { isAbsolute } from 'pathe'; | ||
| import assert from 'node:assert'; | ||
| import v8 from 'node:v8'; | ||
| import { format, inspect } from 'node:util'; | ||
| const JOIN_LEADING_SLASH_RE = /^\.?\//; | ||
| function withTrailingSlash(input = "", respectQueryAndFragment) { | ||
| { | ||
| return input.endsWith("/") ? input : input + "/"; | ||
| } | ||
| } | ||
| function isNonEmptyURL(url) { | ||
| return url && url !== "/"; | ||
| } | ||
| function joinURL(base, ...input) { | ||
| let url = base || ""; | ||
| for (const segment of input.filter((url2) => isNonEmptyURL(url2))) { | ||
| if (url) { | ||
| const _segment = segment.replace(JOIN_LEADING_SLASH_RE, ""); | ||
| url = withTrailingSlash(url) + _segment; | ||
| } else { | ||
| url = segment; | ||
| } | ||
| } | ||
| return url; | ||
| } | ||
| const BUILTIN_MODULES = new Set(builtinModules); | ||
| function normalizeSlash(path) { | ||
| return path.replace(/\\/g, "/"); | ||
| } | ||
| /** | ||
| * @typedef ErrnoExceptionFields | ||
| * @property {number | undefined} [errnode] | ||
| * @property {string | undefined} [code] | ||
| * @property {string | undefined} [path] | ||
| * @property {string | undefined} [syscall] | ||
| * @property {string | undefined} [url] | ||
| * | ||
| * @typedef {Error & ErrnoExceptionFields} ErrnoException | ||
| */ | ||
| const own$1 = {}.hasOwnProperty; | ||
| const classRegExp = /^([A-Z][a-z\d]*)+$/; | ||
| // Sorted by a rough estimate on most frequently used entries. | ||
| const kTypes = new Set([ | ||
| 'string', | ||
| 'function', | ||
| 'number', | ||
| 'object', | ||
| // Accept 'Function' and 'Object' as alternative to the lower cased version. | ||
| 'Function', | ||
| 'Object', | ||
| 'boolean', | ||
| 'bigint', | ||
| 'symbol' | ||
| ]); | ||
| const codes = {}; | ||
| /** | ||
| * Create a list string in the form like 'A and B' or 'A, B, ..., and Z'. | ||
| * We cannot use Intl.ListFormat because it's not available in | ||
| * --without-intl builds. | ||
| * | ||
| * @param {Array<string>} array | ||
| * An array of strings. | ||
| * @param {string} [type] | ||
| * The list type to be inserted before the last element. | ||
| * @returns {string} | ||
| */ | ||
| function formatList(array, type = 'and') { | ||
| return array.length < 3 | ||
| ? array.join(` ${type} `) | ||
| : `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}` | ||
| } | ||
| /** @type {Map<string, MessageFunction | string>} */ | ||
| const messages = new Map(); | ||
| const nodeInternalPrefix = '__node_internal_'; | ||
| /** @type {number} */ | ||
| let userStackTraceLimit; | ||
| codes.ERR_INVALID_ARG_TYPE = createError( | ||
| 'ERR_INVALID_ARG_TYPE', | ||
| /** | ||
| * @param {string} name | ||
| * @param {Array<string> | string} expected | ||
| * @param {unknown} actual | ||
| */ | ||
| (name, expected, actual) => { | ||
| assert(typeof name === 'string', "'name' must be a string"); | ||
| if (!Array.isArray(expected)) { | ||
| expected = [expected]; | ||
| } | ||
| let message = 'The '; | ||
| if (name.endsWith(' argument')) { | ||
| // For cases like 'first argument' | ||
| message += `${name} `; | ||
| } else { | ||
| const type = name.includes('.') ? 'property' : 'argument'; | ||
| message += `"${name}" ${type} `; | ||
| } | ||
| message += 'must be '; | ||
| /** @type {Array<string>} */ | ||
| const types = []; | ||
| /** @type {Array<string>} */ | ||
| const instances = []; | ||
| /** @type {Array<string>} */ | ||
| const other = []; | ||
| for (const value of expected) { | ||
| assert( | ||
| typeof value === 'string', | ||
| 'All expected entries have to be of type string' | ||
| ); | ||
| if (kTypes.has(value)) { | ||
| types.push(value.toLowerCase()); | ||
| } else if (classRegExp.exec(value) === null) { | ||
| assert( | ||
| value !== 'object', | ||
| 'The value "object" should be written as "Object"' | ||
| ); | ||
| other.push(value); | ||
| } else { | ||
| instances.push(value); | ||
| } | ||
| } | ||
| // Special handle `object` in case other instances are allowed to outline | ||
| // the differences between each other. | ||
| if (instances.length > 0) { | ||
| const pos = types.indexOf('object'); | ||
| if (pos !== -1) { | ||
| types.slice(pos, 1); | ||
| instances.push('Object'); | ||
| } | ||
| } | ||
| if (types.length > 0) { | ||
| message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList( | ||
| types, | ||
| 'or' | ||
| )}`; | ||
| if (instances.length > 0 || other.length > 0) message += ' or '; | ||
| } | ||
| if (instances.length > 0) { | ||
| message += `an instance of ${formatList(instances, 'or')}`; | ||
| if (other.length > 0) message += ' or '; | ||
| } | ||
| if (other.length > 0) { | ||
| if (other.length > 1) { | ||
| message += `one of ${formatList(other, 'or')}`; | ||
| } else { | ||
| if (other[0].toLowerCase() !== other[0]) message += 'an '; | ||
| message += `${other[0]}`; | ||
| } | ||
| } | ||
| message += `. Received ${determineSpecificType(actual)}`; | ||
| return message | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_INVALID_MODULE_SPECIFIER = createError( | ||
| 'ERR_INVALID_MODULE_SPECIFIER', | ||
| /** | ||
| * @param {string} request | ||
| * @param {string} reason | ||
| * @param {string} [base] | ||
| */ | ||
| (request, reason, base = undefined) => { | ||
| return `Invalid module "${request}" ${reason}${ | ||
| base ? ` imported from ${base}` : '' | ||
| }` | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_INVALID_PACKAGE_CONFIG = createError( | ||
| 'ERR_INVALID_PACKAGE_CONFIG', | ||
| /** | ||
| * @param {string} path | ||
| * @param {string} [base] | ||
| * @param {string} [message] | ||
| */ | ||
| (path, base, message) => { | ||
| return `Invalid package config ${path}${ | ||
| base ? ` while importing ${base}` : '' | ||
| }${message ? `. ${message}` : ''}` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_INVALID_PACKAGE_TARGET = createError( | ||
| 'ERR_INVALID_PACKAGE_TARGET', | ||
| /** | ||
| * @param {string} packagePath | ||
| * @param {string} key | ||
| * @param {unknown} target | ||
| * @param {boolean} [isImport=false] | ||
| * @param {string} [base] | ||
| */ | ||
| (packagePath, key, target, isImport = false, base = undefined) => { | ||
| const relatedError = | ||
| typeof target === 'string' && | ||
| !isImport && | ||
| target.length > 0 && | ||
| !target.startsWith('./'); | ||
| if (key === '.') { | ||
| assert(isImport === false); | ||
| return ( | ||
| `Invalid "exports" main target ${JSON.stringify(target)} defined ` + | ||
| `in the package config ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }${relatedError ? '; targets must start with "./"' : ''}` | ||
| ) | ||
| } | ||
| return `Invalid "${ | ||
| isImport ? 'imports' : 'exports' | ||
| }" target ${JSON.stringify( | ||
| target | ||
| )} defined for '${key}' in the package config ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }${relatedError ? '; targets must start with "./"' : ''}` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_MODULE_NOT_FOUND = createError( | ||
| 'ERR_MODULE_NOT_FOUND', | ||
| /** | ||
| * @param {string} path | ||
| * @param {string} base | ||
| * @param {boolean} [exactUrl] | ||
| */ | ||
| (path, base, exactUrl = false) => { | ||
| return `Cannot find ${ | ||
| exactUrl ? 'module' : 'package' | ||
| } '${path}' imported from ${base}` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_NETWORK_IMPORT_DISALLOWED = createError( | ||
| 'ERR_NETWORK_IMPORT_DISALLOWED', | ||
| "import of '%s' by %s is not supported: %s", | ||
| Error | ||
| ); | ||
| codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError( | ||
| 'ERR_PACKAGE_IMPORT_NOT_DEFINED', | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {string} packagePath | ||
| * @param {string} base | ||
| */ | ||
| (specifier, packagePath, base) => { | ||
| return `Package import specifier "${specifier}" is not defined${ | ||
| packagePath ? ` in package ${packagePath}package.json` : '' | ||
| } imported from ${base}` | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError( | ||
| 'ERR_PACKAGE_PATH_NOT_EXPORTED', | ||
| /** | ||
| * @param {string} packagePath | ||
| * @param {string} subpath | ||
| * @param {string} [base] | ||
| */ | ||
| (packagePath, subpath, base = undefined) => { | ||
| if (subpath === '.') | ||
| return `No "exports" main defined in ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }` | ||
| return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${ | ||
| base ? ` imported from ${base}` : '' | ||
| }` | ||
| }, | ||
| Error | ||
| ); | ||
| codes.ERR_UNSUPPORTED_DIR_IMPORT = createError( | ||
| 'ERR_UNSUPPORTED_DIR_IMPORT', | ||
| "Directory import '%s' is not supported " + | ||
| 'resolving ES modules imported from %s', | ||
| Error | ||
| ); | ||
| codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError( | ||
| 'ERR_UNSUPPORTED_RESOLVE_REQUEST', | ||
| 'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.', | ||
| TypeError | ||
| ); | ||
| codes.ERR_UNKNOWN_FILE_EXTENSION = createError( | ||
| 'ERR_UNKNOWN_FILE_EXTENSION', | ||
| /** | ||
| * @param {string} extension | ||
| * @param {string} path | ||
| */ | ||
| (extension, path) => { | ||
| return `Unknown file extension "${extension}" for ${path}` | ||
| }, | ||
| TypeError | ||
| ); | ||
| codes.ERR_INVALID_ARG_VALUE = createError( | ||
| 'ERR_INVALID_ARG_VALUE', | ||
| /** | ||
| * @param {string} name | ||
| * @param {unknown} value | ||
| * @param {string} [reason='is invalid'] | ||
| */ | ||
| (name, value, reason = 'is invalid') => { | ||
| let inspected = inspect(value); | ||
| if (inspected.length > 128) { | ||
| inspected = `${inspected.slice(0, 128)}...`; | ||
| } | ||
| const type = name.includes('.') ? 'property' : 'argument'; | ||
| return `The ${type} '${name}' ${reason}. Received ${inspected}` | ||
| }, | ||
| TypeError | ||
| // Note: extra classes have been shaken out. | ||
| // , RangeError | ||
| ); | ||
| /** | ||
| * Utility function for registering the error codes. Only used here. Exported | ||
| * *only* to allow for testing. | ||
| * @param {string} sym | ||
| * @param {MessageFunction | string} value | ||
| * @param {ErrorConstructor} constructor | ||
| * @returns {new (...parameters: Array<any>) => Error} | ||
| */ | ||
| function createError(sym, value, constructor) { | ||
| // Special case for SystemError that formats the error message differently | ||
| // The SystemErrors only have SystemError as their base classes. | ||
| messages.set(sym, value); | ||
| return makeNodeErrorWithCode(constructor, sym) | ||
| } | ||
| /** | ||
| * @param {ErrorConstructor} Base | ||
| * @param {string} key | ||
| * @returns {ErrorConstructor} | ||
| */ | ||
| function makeNodeErrorWithCode(Base, key) { | ||
| // @ts-expect-error It’s a Node error. | ||
| return NodeError | ||
| /** | ||
| * @param {Array<unknown>} parameters | ||
| */ | ||
| function NodeError(...parameters) { | ||
| const limit = Error.stackTraceLimit; | ||
| if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0; | ||
| const error = new Base(); | ||
| // Reset the limit and setting the name property. | ||
| if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit; | ||
| const message = getMessage(key, parameters, error); | ||
| Object.defineProperties(error, { | ||
| // Note: no need to implement `kIsNodeError` symbol, would be hard, | ||
| // probably. | ||
| message: { | ||
| value: message, | ||
| enumerable: false, | ||
| writable: true, | ||
| configurable: true | ||
| }, | ||
| toString: { | ||
| /** @this {Error} */ | ||
| value() { | ||
| return `${this.name} [${key}]: ${this.message}` | ||
| }, | ||
| enumerable: false, | ||
| writable: true, | ||
| configurable: true | ||
| } | ||
| }); | ||
| captureLargerStackTrace(error); | ||
| // @ts-expect-error It’s a Node error. | ||
| error.code = key; | ||
| return error | ||
| } | ||
| } | ||
| /** | ||
| * @returns {boolean} | ||
| */ | ||
| function isErrorStackTraceLimitWritable() { | ||
| // Do no touch Error.stackTraceLimit as V8 would attempt to install | ||
| // it again during deserialization. | ||
| try { | ||
| if (v8.startupSnapshot.isBuildingSnapshot()) { | ||
| return false | ||
| } | ||
| } catch {} | ||
| const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit'); | ||
| if (desc === undefined) { | ||
| return Object.isExtensible(Error) | ||
| } | ||
| return own$1.call(desc, 'writable') && desc.writable !== undefined | ||
| ? desc.writable | ||
| : desc.set !== undefined | ||
| } | ||
| /** | ||
| * This function removes unnecessary frames from Node.js core errors. | ||
| * @template {(...parameters: unknown[]) => unknown} T | ||
| * @param {T} wrappedFunction | ||
| * @returns {T} | ||
| */ | ||
| function hideStackFrames(wrappedFunction) { | ||
| // We rename the functions that will be hidden to cut off the stacktrace | ||
| // at the outermost one | ||
| const hidden = nodeInternalPrefix + wrappedFunction.name; | ||
| Object.defineProperty(wrappedFunction, 'name', {value: hidden}); | ||
| return wrappedFunction | ||
| } | ||
| const captureLargerStackTrace = hideStackFrames( | ||
| /** | ||
| * @param {Error} error | ||
| * @returns {Error} | ||
| */ | ||
| // @ts-expect-error: fine | ||
| function (error) { | ||
| const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable(); | ||
| if (stackTraceLimitIsWritable) { | ||
| userStackTraceLimit = Error.stackTraceLimit; | ||
| Error.stackTraceLimit = Number.POSITIVE_INFINITY; | ||
| } | ||
| Error.captureStackTrace(error); | ||
| // Reset the limit | ||
| if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit; | ||
| return error | ||
| } | ||
| ); | ||
| /** | ||
| * @param {string} key | ||
| * @param {Array<unknown>} parameters | ||
| * @param {Error} self | ||
| * @returns {string} | ||
| */ | ||
| function getMessage(key, parameters, self) { | ||
| const message = messages.get(key); | ||
| assert(message !== undefined, 'expected `message` to be found'); | ||
| if (typeof message === 'function') { | ||
| assert( | ||
| message.length <= parameters.length, // Default options do not count. | ||
| `Code: ${key}; The provided arguments length (${parameters.length}) does not ` + | ||
| `match the required ones (${message.length}).` | ||
| ); | ||
| return Reflect.apply(message, self, parameters) | ||
| } | ||
| const regex = /%[dfijoOs]/g; | ||
| let expectedLength = 0; | ||
| while (regex.exec(message) !== null) expectedLength++; | ||
| assert( | ||
| expectedLength === parameters.length, | ||
| `Code: ${key}; The provided arguments length (${parameters.length}) does not ` + | ||
| `match the required ones (${expectedLength}).` | ||
| ); | ||
| if (parameters.length === 0) return message | ||
| parameters.unshift(message); | ||
| return Reflect.apply(format, null, parameters) | ||
| } | ||
| /** | ||
| * Determine the specific type of a value for type-mismatch errors. | ||
| * @param {unknown} value | ||
| * @returns {string} | ||
| */ | ||
| function determineSpecificType(value) { | ||
| if (value === null || value === undefined) { | ||
| return String(value) | ||
| } | ||
| if (typeof value === 'function' && value.name) { | ||
| return `function ${value.name}` | ||
| } | ||
| if (typeof value === 'object') { | ||
| if (value.constructor && value.constructor.name) { | ||
| return `an instance of ${value.constructor.name}` | ||
| } | ||
| return `${inspect(value, {depth: -1})}` | ||
| } | ||
| let inspected = inspect(value, {colors: false}); | ||
| if (inspected.length > 28) { | ||
| inspected = `${inspected.slice(0, 25)}...`; | ||
| } | ||
| return `type ${typeof value} (${inspected})` | ||
| } | ||
| // Manually “tree shaken” from: | ||
| // <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/package_json_reader.js> | ||
| // Last checked on: Apr 29, 2023. | ||
| // Removed the native dependency. | ||
| // Also: no need to cache, we do that in resolve already. | ||
| const hasOwnProperty$1 = {}.hasOwnProperty; | ||
| const {ERR_INVALID_PACKAGE_CONFIG: ERR_INVALID_PACKAGE_CONFIG$1} = codes; | ||
| /** @type {Map<string, PackageConfig>} */ | ||
| const cache = new Map(); | ||
| /** | ||
| * @param {string} jsonPath | ||
| * @param {{specifier: URL | string, base?: URL}} options | ||
| * @returns {PackageConfig} | ||
| */ | ||
| function read(jsonPath, {base, specifier}) { | ||
| const existing = cache.get(jsonPath); | ||
| if (existing) { | ||
| return existing | ||
| } | ||
| /** @type {string | undefined} */ | ||
| let string; | ||
| try { | ||
| string = fs__default.readFileSync(path.toNamespacedPath(jsonPath), 'utf8'); | ||
| } catch (error) { | ||
| const exception = /** @type {ErrnoException} */ (error); | ||
| if (exception.code !== 'ENOENT') { | ||
| throw exception | ||
| } | ||
| } | ||
| /** @type {PackageConfig} */ | ||
| const result = { | ||
| exists: false, | ||
| pjsonPath: jsonPath, | ||
| main: undefined, | ||
| name: undefined, | ||
| type: 'none', // Ignore unknown types for forwards compatibility | ||
| exports: undefined, | ||
| imports: undefined | ||
| }; | ||
| if (string !== undefined) { | ||
| /** @type {Record<string, unknown>} */ | ||
| let parsed; | ||
| try { | ||
| parsed = JSON.parse(string); | ||
| } catch (error_) { | ||
| const cause = /** @type {ErrnoException} */ (error_); | ||
| const error = new ERR_INVALID_PACKAGE_CONFIG$1( | ||
| jsonPath, | ||
| (base ? `"${specifier}" from ` : '') + fileURLToPath$1(base || specifier), | ||
| cause.message | ||
| ); | ||
| error.cause = cause; | ||
| throw error | ||
| } | ||
| result.exists = true; | ||
| if ( | ||
| hasOwnProperty$1.call(parsed, 'name') && | ||
| typeof parsed.name === 'string' | ||
| ) { | ||
| result.name = parsed.name; | ||
| } | ||
| if ( | ||
| hasOwnProperty$1.call(parsed, 'main') && | ||
| typeof parsed.main === 'string' | ||
| ) { | ||
| result.main = parsed.main; | ||
| } | ||
| if (hasOwnProperty$1.call(parsed, 'exports')) { | ||
| // @ts-expect-error: assume valid. | ||
| result.exports = parsed.exports; | ||
| } | ||
| if (hasOwnProperty$1.call(parsed, 'imports')) { | ||
| // @ts-expect-error: assume valid. | ||
| result.imports = parsed.imports; | ||
| } | ||
| // Ignore unknown types for forwards compatibility | ||
| if ( | ||
| hasOwnProperty$1.call(parsed, 'type') && | ||
| (parsed.type === 'commonjs' || parsed.type === 'module') | ||
| ) { | ||
| result.type = parsed.type; | ||
| } | ||
| } | ||
| cache.set(jsonPath, result); | ||
| return result | ||
| } | ||
| /** | ||
| * @param {URL | string} resolved | ||
| * @returns {PackageConfig} | ||
| */ | ||
| function getPackageScopeConfig(resolved) { | ||
| // Note: in Node, this is now a native module. | ||
| let packageJSONUrl = new URL('package.json', resolved); | ||
| while (true) { | ||
| const packageJSONPath = packageJSONUrl.pathname; | ||
| if (packageJSONPath.endsWith('node_modules/package.json')) { | ||
| break | ||
| } | ||
| const packageConfig = read(fileURLToPath$1(packageJSONUrl), { | ||
| specifier: resolved | ||
| }); | ||
| if (packageConfig.exists) { | ||
| return packageConfig | ||
| } | ||
| const lastPackageJSONUrl = packageJSONUrl; | ||
| packageJSONUrl = new URL('../package.json', packageJSONUrl); | ||
| // Terminates at root where ../package.json equals ../../package.json | ||
| // (can't just check "/package.json" for Windows support). | ||
| if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) { | ||
| break | ||
| } | ||
| } | ||
| const packageJSONPath = fileURLToPath$1(packageJSONUrl); | ||
| // ^^ Note: in Node, this is now a native module. | ||
| return { | ||
| pjsonPath: packageJSONPath, | ||
| exists: false, | ||
| type: 'none' | ||
| } | ||
| } | ||
| /** | ||
| * Returns the package type for a given URL. | ||
| * @param {URL} url - The URL to get the package type for. | ||
| * @returns {PackageType} | ||
| */ | ||
| function getPackageType(url) { | ||
| // To do @anonrig: Write a C++ function that returns only "type". | ||
| return getPackageScopeConfig(url).type | ||
| } | ||
| // Manually “tree shaken” from: | ||
| // <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js> | ||
| // Last checked on: Apr 29, 2023. | ||
| const {ERR_UNKNOWN_FILE_EXTENSION} = codes; | ||
| const hasOwnProperty = {}.hasOwnProperty; | ||
| /** @type {Record<string, string>} */ | ||
| const extensionFormatMap = { | ||
| // @ts-expect-error: hush. | ||
| __proto__: null, | ||
| '.cjs': 'commonjs', | ||
| '.js': 'module', | ||
| '.json': 'json', | ||
| '.mjs': 'module' | ||
| }; | ||
| /** | ||
| * @param {string | null} mime | ||
| * @returns {string | null} | ||
| */ | ||
| function mimeToFormat(mime) { | ||
| if ( | ||
| mime && | ||
| /\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i.test(mime) | ||
| ) | ||
| return 'module' | ||
| if (mime === 'application/json') return 'json' | ||
| return null | ||
| } | ||
| /** | ||
| * @callback ProtocolHandler | ||
| * @param {URL} parsed | ||
| * @param {{parentURL: string, source?: Buffer}} context | ||
| * @param {boolean} ignoreErrors | ||
| * @returns {string | null | void} | ||
| */ | ||
| /** | ||
| * @type {Record<string, ProtocolHandler>} | ||
| */ | ||
| const protocolHandlers = { | ||
| // @ts-expect-error: hush. | ||
| __proto__: null, | ||
| 'data:': getDataProtocolModuleFormat, | ||
| 'file:': getFileProtocolModuleFormat, | ||
| 'http:': getHttpProtocolModuleFormat, | ||
| 'https:': getHttpProtocolModuleFormat, | ||
| 'node:'() { | ||
| return 'builtin' | ||
| } | ||
| }; | ||
| /** | ||
| * @param {URL} parsed | ||
| */ | ||
| function getDataProtocolModuleFormat(parsed) { | ||
| const {1: mime} = /^([^/]+\/[^;,]+)[^,]*?(;base64)?,/.exec( | ||
| parsed.pathname | ||
| ) || [null, null, null]; | ||
| return mimeToFormat(mime) | ||
| } | ||
| /** | ||
| * Returns the file extension from a URL. | ||
| * | ||
| * Should give similar result to | ||
| * `require('node:path').extname(require('node:url').fileURLToPath(url))` | ||
| * when used with a `file:` URL. | ||
| * | ||
| * @param {URL} url | ||
| * @returns {string} | ||
| */ | ||
| function extname(url) { | ||
| const pathname = url.pathname; | ||
| let index = pathname.length; | ||
| while (index--) { | ||
| const code = pathname.codePointAt(index); | ||
| if (code === 47 /* `/` */) { | ||
| return '' | ||
| } | ||
| if (code === 46 /* `.` */) { | ||
| return pathname.codePointAt(index - 1) === 47 /* `/` */ | ||
| ? '' | ||
| : pathname.slice(index) | ||
| } | ||
| } | ||
| return '' | ||
| } | ||
| /** | ||
| * @type {ProtocolHandler} | ||
| */ | ||
| function getFileProtocolModuleFormat(url, _context, ignoreErrors) { | ||
| const value = extname(url); | ||
| if (value === '.js') { | ||
| const packageType = getPackageType(url); | ||
| if (packageType !== 'none') { | ||
| return packageType | ||
| } | ||
| return 'commonjs' | ||
| } | ||
| if (value === '') { | ||
| const packageType = getPackageType(url); | ||
| // Legacy behavior | ||
| if (packageType === 'none' || packageType === 'commonjs') { | ||
| return 'commonjs' | ||
| } | ||
| // Note: we don’t implement WASM, so we don’t need | ||
| // `getFormatOfExtensionlessFile` from `formats`. | ||
| return 'module' | ||
| } | ||
| const format = extensionFormatMap[value]; | ||
| if (format) return format | ||
| // Explicit undefined return indicates load hook should rerun format check | ||
| if (ignoreErrors) { | ||
| return undefined | ||
| } | ||
| const filepath = fileURLToPath$1(url); | ||
| throw new ERR_UNKNOWN_FILE_EXTENSION(value, filepath) | ||
| } | ||
| function getHttpProtocolModuleFormat() { | ||
| // To do: HTTPS imports. | ||
| } | ||
| /** | ||
| * @param {URL} url | ||
| * @param {{parentURL: string}} context | ||
| * @returns {string | null} | ||
| */ | ||
| function defaultGetFormatWithoutErrors(url, context) { | ||
| const protocol = url.protocol; | ||
| if (!hasOwnProperty.call(protocolHandlers, protocol)) { | ||
| return null | ||
| } | ||
| return protocolHandlers[protocol](url, context, true) || null | ||
| } | ||
| // Manually “tree shaken” from: | ||
| // <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/resolve.js> | ||
| // Last checked on: Apr 29, 2023. | ||
| const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace]; | ||
| const { | ||
| ERR_INVALID_MODULE_SPECIFIER, | ||
| ERR_INVALID_PACKAGE_CONFIG, | ||
| ERR_INVALID_PACKAGE_TARGET, | ||
| ERR_MODULE_NOT_FOUND, | ||
| ERR_PACKAGE_IMPORT_NOT_DEFINED, | ||
| ERR_PACKAGE_PATH_NOT_EXPORTED, | ||
| ERR_UNSUPPORTED_DIR_IMPORT, | ||
| ERR_UNSUPPORTED_RESOLVE_REQUEST | ||
| } = codes; | ||
| const own = {}.hasOwnProperty; | ||
| const invalidSegmentRegEx = | ||
| /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i; | ||
| const deprecatedInvalidSegmentRegEx = | ||
| /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i; | ||
| const invalidPackageNameRegEx = /^\.|%|\\/; | ||
| const patternRegEx = /\*/g; | ||
| const encodedSeparatorRegEx = /%2f|%5c/i; | ||
| /** @type {Set<string>} */ | ||
| const emittedPackageWarnings = new Set(); | ||
| const doubleSlashRegEx = /[/\\]{2}/; | ||
| /** | ||
| * | ||
| * @param {string} target | ||
| * @param {string} request | ||
| * @param {string} match | ||
| * @param {URL} packageJsonUrl | ||
| * @param {boolean} internal | ||
| * @param {URL} base | ||
| * @param {boolean} isTarget | ||
| */ | ||
| function emitInvalidSegmentDeprecation( | ||
| target, | ||
| request, | ||
| match, | ||
| packageJsonUrl, | ||
| internal, | ||
| base, | ||
| isTarget | ||
| ) { | ||
| // @ts-expect-error: apparently it does exist, TS. | ||
| if (process$1.noDeprecation) { | ||
| return | ||
| } | ||
| const pjsonPath = fileURLToPath$1(packageJsonUrl); | ||
| const double = doubleSlashRegEx.exec(isTarget ? target : request) !== null; | ||
| process$1.emitWarning( | ||
| `Use of deprecated ${ | ||
| double ? 'double slash' : 'leading or trailing slash matching' | ||
| } resolving "${target}" for module ` + | ||
| `request "${request}" ${ | ||
| request === match ? '' : `matched to "${match}" ` | ||
| }in the "${ | ||
| internal ? 'imports' : 'exports' | ||
| }" field module resolution of the package at ${pjsonPath}${ | ||
| base ? ` imported from ${fileURLToPath$1(base)}` : '' | ||
| }.`, | ||
| 'DeprecationWarning', | ||
| 'DEP0166' | ||
| ); | ||
| } | ||
| /** | ||
| * @param {URL} url | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @param {string} [main] | ||
| * @returns {void} | ||
| */ | ||
| function emitLegacyIndexDeprecation(url, packageJsonUrl, base, main) { | ||
| // @ts-expect-error: apparently it does exist, TS. | ||
| if (process$1.noDeprecation) { | ||
| return | ||
| } | ||
| const format = defaultGetFormatWithoutErrors(url, {parentURL: base.href}); | ||
| if (format !== 'module') return | ||
| const urlPath = fileURLToPath$1(url.href); | ||
| const packagePath = fileURLToPath$1(new URL$1('.', packageJsonUrl)); | ||
| const basePath = fileURLToPath$1(base); | ||
| if (!main) { | ||
| process$1.emitWarning( | ||
| `No "main" or "exports" field defined in the package.json for ${packagePath} resolving the main entry point "${urlPath.slice( | ||
| packagePath.length | ||
| )}", imported from ${basePath}.\nDefault "index" lookups for the main are deprecated for ES modules.`, | ||
| 'DeprecationWarning', | ||
| 'DEP0151' | ||
| ); | ||
| } else if (path.resolve(packagePath, main) !== urlPath) { | ||
| process$1.emitWarning( | ||
| `Package ${packagePath} has a "main" field set to "${main}", ` + | ||
| `excluding the full filename and extension to the resolved file at "${urlPath.slice( | ||
| packagePath.length | ||
| )}", imported from ${basePath}.\n Automatic extension resolution of the "main" field is ` + | ||
| 'deprecated for ES modules.', | ||
| 'DeprecationWarning', | ||
| 'DEP0151' | ||
| ); | ||
| } | ||
| } | ||
| /** | ||
| * @param {string} path | ||
| * @returns {Stats | undefined} | ||
| */ | ||
| function tryStatSync(path) { | ||
| // Note: from Node 15 onwards we can use `throwIfNoEntry: false` instead. | ||
| try { | ||
| return statSync(path) | ||
| } catch { | ||
| // Note: in Node code this returns `new Stats`, | ||
| // but in Node 22 that’s marked as a deprecated internal API. | ||
| // Which, well, we kinda are, but still to prevent that warning, | ||
| // just yield `undefined`. | ||
| } | ||
| } | ||
| /** | ||
| * Legacy CommonJS main resolution: | ||
| * 1. let M = pkg_url + (json main field) | ||
| * 2. TRY(M, M.js, M.json, M.node) | ||
| * 3. TRY(M/index.js, M/index.json, M/index.node) | ||
| * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node) | ||
| * 5. NOT_FOUND | ||
| * | ||
| * @param {URL} url | ||
| * @returns {boolean} | ||
| */ | ||
| function fileExists(url) { | ||
| const stats = statSync(url, {throwIfNoEntry: false}); | ||
| const isFile = stats ? stats.isFile() : undefined; | ||
| return isFile === null || isFile === undefined ? false : isFile | ||
| } | ||
| /** | ||
| * @param {URL} packageJsonUrl | ||
| * @param {PackageConfig} packageConfig | ||
| * @param {URL} base | ||
| * @returns {URL} | ||
| */ | ||
| function legacyMainResolve(packageJsonUrl, packageConfig, base) { | ||
| /** @type {URL | undefined} */ | ||
| let guess; | ||
| if (packageConfig.main !== undefined) { | ||
| guess = new URL$1(packageConfig.main, packageJsonUrl); | ||
| // Note: fs check redundances will be handled by Descriptor cache here. | ||
| if (fileExists(guess)) return guess | ||
| const tries = [ | ||
| `./${packageConfig.main}.js`, | ||
| `./${packageConfig.main}.json`, | ||
| `./${packageConfig.main}.node`, | ||
| `./${packageConfig.main}/index.js`, | ||
| `./${packageConfig.main}/index.json`, | ||
| `./${packageConfig.main}/index.node` | ||
| ]; | ||
| let i = -1; | ||
| while (++i < tries.length) { | ||
| guess = new URL$1(tries[i], packageJsonUrl); | ||
| if (fileExists(guess)) break | ||
| guess = undefined; | ||
| } | ||
| if (guess) { | ||
| emitLegacyIndexDeprecation( | ||
| guess, | ||
| packageJsonUrl, | ||
| base, | ||
| packageConfig.main | ||
| ); | ||
| return guess | ||
| } | ||
| // Fallthrough. | ||
| } | ||
| const tries = ['./index.js', './index.json', './index.node']; | ||
| let i = -1; | ||
| while (++i < tries.length) { | ||
| guess = new URL$1(tries[i], packageJsonUrl); | ||
| if (fileExists(guess)) break | ||
| guess = undefined; | ||
| } | ||
| if (guess) { | ||
| emitLegacyIndexDeprecation(guess, packageJsonUrl, base, packageConfig.main); | ||
| return guess | ||
| } | ||
| // Not found. | ||
| throw new ERR_MODULE_NOT_FOUND( | ||
| fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {URL} resolved | ||
| * @param {URL} base | ||
| * @param {boolean} [preserveSymlinks] | ||
| * @returns {URL} | ||
| */ | ||
| function finalizeResolution(resolved, base, preserveSymlinks) { | ||
| if (encodedSeparatorRegEx.exec(resolved.pathname) !== null) { | ||
| throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| resolved.pathname, | ||
| 'must not include encoded "/" or "\\" characters', | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** @type {string} */ | ||
| let filePath; | ||
| try { | ||
| filePath = fileURLToPath$1(resolved); | ||
| } catch (error) { | ||
| const cause = /** @type {ErrnoException} */ (error); | ||
| Object.defineProperty(cause, 'input', {value: String(resolved)}); | ||
| Object.defineProperty(cause, 'module', {value: String(base)}); | ||
| throw cause | ||
| } | ||
| const stats = tryStatSync( | ||
| filePath.endsWith('/') ? filePath.slice(-1) : filePath | ||
| ); | ||
| if (stats && stats.isDirectory()) { | ||
| const error = new ERR_UNSUPPORTED_DIR_IMPORT(filePath, fileURLToPath$1(base)); | ||
| // @ts-expect-error Add this for `import.meta.resolve`. | ||
| error.url = String(resolved); | ||
| throw error | ||
| } | ||
| if (!stats || !stats.isFile()) { | ||
| const error = new ERR_MODULE_NOT_FOUND( | ||
| filePath || resolved.pathname, | ||
| base && fileURLToPath$1(base), | ||
| true | ||
| ); | ||
| // @ts-expect-error Add this for `import.meta.resolve`. | ||
| error.url = String(resolved); | ||
| throw error | ||
| } | ||
| { | ||
| const real = realpathSync(filePath); | ||
| const {search, hash} = resolved; | ||
| resolved = pathToFileURL$1(real + (filePath.endsWith(path.sep) ? '/' : '')); | ||
| resolved.search = search; | ||
| resolved.hash = hash; | ||
| } | ||
| return resolved | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {URL | undefined} packageJsonUrl | ||
| * @param {URL} base | ||
| * @returns {Error} | ||
| */ | ||
| function importNotDefined(specifier, packageJsonUrl, base) { | ||
| return new ERR_PACKAGE_IMPORT_NOT_DEFINED( | ||
| specifier, | ||
| packageJsonUrl && fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} subpath | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @returns {Error} | ||
| */ | ||
| function exportsNotFound(subpath, packageJsonUrl, base) { | ||
| return new ERR_PACKAGE_PATH_NOT_EXPORTED( | ||
| fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| subpath, | ||
| base && fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} request | ||
| * @param {string} match | ||
| * @param {URL} packageJsonUrl | ||
| * @param {boolean} internal | ||
| * @param {URL} [base] | ||
| * @returns {never} | ||
| */ | ||
| function throwInvalidSubpath(request, match, packageJsonUrl, internal, base) { | ||
| const reason = `request is not a valid match in pattern "${match}" for the "${ | ||
| internal ? 'imports' : 'exports' | ||
| }" resolution of ${fileURLToPath$1(packageJsonUrl)}`; | ||
| throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| request, | ||
| reason, | ||
| base && fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} subpath | ||
| * @param {unknown} target | ||
| * @param {URL} packageJsonUrl | ||
| * @param {boolean} internal | ||
| * @param {URL} [base] | ||
| * @returns {Error} | ||
| */ | ||
| function invalidPackageTarget(subpath, target, packageJsonUrl, internal, base) { | ||
| target = | ||
| typeof target === 'object' && target !== null | ||
| ? JSON.stringify(target, null, '') | ||
| : `${target}`; | ||
| return new ERR_INVALID_PACKAGE_TARGET( | ||
| fileURLToPath$1(new URL$1('.', packageJsonUrl)), | ||
| subpath, | ||
| target, | ||
| internal, | ||
| base && fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| /** | ||
| * @param {string} target | ||
| * @param {string} subpath | ||
| * @param {string} match | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @param {boolean} pattern | ||
| * @param {boolean} internal | ||
| * @param {boolean} isPathMap | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL} | ||
| */ | ||
| function resolvePackageTargetString( | ||
| target, | ||
| subpath, | ||
| match, | ||
| packageJsonUrl, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ) { | ||
| if (subpath !== '' && !pattern && target[target.length - 1] !== '/') | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| if (!target.startsWith('./')) { | ||
| if (internal && !target.startsWith('../') && !target.startsWith('/')) { | ||
| let isURL = false; | ||
| try { | ||
| new URL$1(target); | ||
| isURL = true; | ||
| } catch { | ||
| // Continue regardless of error. | ||
| } | ||
| if (!isURL) { | ||
| const exportTarget = pattern | ||
| ? RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| target, | ||
| () => subpath | ||
| ) | ||
| : target + subpath; | ||
| return packageResolve(exportTarget, packageJsonUrl, conditions) | ||
| } | ||
| } | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| } | ||
| if (invalidSegmentRegEx.exec(target.slice(2)) !== null) { | ||
| if (deprecatedInvalidSegmentRegEx.exec(target.slice(2)) === null) { | ||
| if (!isPathMap) { | ||
| const request = pattern | ||
| ? match.replace('*', () => subpath) | ||
| : match + subpath; | ||
| const resolvedTarget = pattern | ||
| ? RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| target, | ||
| () => subpath | ||
| ) | ||
| : target; | ||
| emitInvalidSegmentDeprecation( | ||
| resolvedTarget, | ||
| request, | ||
| match, | ||
| packageJsonUrl, | ||
| internal, | ||
| base, | ||
| true | ||
| ); | ||
| } | ||
| } else { | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| } | ||
| } | ||
| const resolved = new URL$1(target, packageJsonUrl); | ||
| const resolvedPath = resolved.pathname; | ||
| const packagePath = new URL$1('.', packageJsonUrl).pathname; | ||
| if (!resolvedPath.startsWith(packagePath)) | ||
| throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) | ||
| if (subpath === '') return resolved | ||
| if (invalidSegmentRegEx.exec(subpath) !== null) { | ||
| const request = pattern | ||
| ? match.replace('*', () => subpath) | ||
| : match + subpath; | ||
| if (deprecatedInvalidSegmentRegEx.exec(subpath) === null) { | ||
| if (!isPathMap) { | ||
| const resolvedTarget = pattern | ||
| ? RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| target, | ||
| () => subpath | ||
| ) | ||
| : target; | ||
| emitInvalidSegmentDeprecation( | ||
| resolvedTarget, | ||
| request, | ||
| match, | ||
| packageJsonUrl, | ||
| internal, | ||
| base, | ||
| false | ||
| ); | ||
| } | ||
| } else { | ||
| throwInvalidSubpath(request, match, packageJsonUrl, internal, base); | ||
| } | ||
| } | ||
| if (pattern) { | ||
| return new URL$1( | ||
| RegExpPrototypeSymbolReplace.call( | ||
| patternRegEx, | ||
| resolved.href, | ||
| () => subpath | ||
| ) | ||
| ) | ||
| } | ||
| return new URL$1(subpath, resolved) | ||
| } | ||
| /** | ||
| * @param {string} key | ||
| * @returns {boolean} | ||
| */ | ||
| function isArrayIndex(key) { | ||
| const keyNumber = Number(key); | ||
| if (`${keyNumber}` !== key) return false | ||
| return keyNumber >= 0 && keyNumber < 0xff_ff_ff_ff | ||
| } | ||
| /** | ||
| * @param {URL} packageJsonUrl | ||
| * @param {unknown} target | ||
| * @param {string} subpath | ||
| * @param {string} packageSubpath | ||
| * @param {URL} base | ||
| * @param {boolean} pattern | ||
| * @param {boolean} internal | ||
| * @param {boolean} isPathMap | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL | null} | ||
| */ | ||
| function resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| subpath, | ||
| packageSubpath, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ) { | ||
| if (typeof target === 'string') { | ||
| return resolvePackageTargetString( | ||
| target, | ||
| subpath, | ||
| packageSubpath, | ||
| packageJsonUrl, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ) | ||
| } | ||
| if (Array.isArray(target)) { | ||
| /** @type {Array<unknown>} */ | ||
| const targetList = target; | ||
| if (targetList.length === 0) return null | ||
| /** @type {ErrnoException | null | undefined} */ | ||
| let lastException; | ||
| let i = -1; | ||
| while (++i < targetList.length) { | ||
| const targetItem = targetList[i]; | ||
| /** @type {URL | null} */ | ||
| let resolveResult; | ||
| try { | ||
| resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| targetItem, | ||
| subpath, | ||
| packageSubpath, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ); | ||
| } catch (error) { | ||
| const exception = /** @type {ErrnoException} */ (error); | ||
| lastException = exception; | ||
| if (exception.code === 'ERR_INVALID_PACKAGE_TARGET') continue | ||
| throw error | ||
| } | ||
| if (resolveResult === undefined) continue | ||
| if (resolveResult === null) { | ||
| lastException = null; | ||
| continue | ||
| } | ||
| return resolveResult | ||
| } | ||
| if (lastException === undefined || lastException === null) { | ||
| return null | ||
| } | ||
| throw lastException | ||
| } | ||
| if (typeof target === 'object' && target !== null) { | ||
| const keys = Object.getOwnPropertyNames(target); | ||
| let i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| if (isArrayIndex(key)) { | ||
| throw new ERR_INVALID_PACKAGE_CONFIG( | ||
| fileURLToPath$1(packageJsonUrl), | ||
| base, | ||
| '"exports" cannot contain numeric property keys.' | ||
| ) | ||
| } | ||
| } | ||
| i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| if (key === 'default' || (conditions && conditions.has(key))) { | ||
| // @ts-expect-error: indexable. | ||
| const conditionalTarget = /** @type {unknown} */ (target[key]); | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| conditionalTarget, | ||
| subpath, | ||
| packageSubpath, | ||
| base, | ||
| pattern, | ||
| internal, | ||
| isPathMap, | ||
| conditions | ||
| ); | ||
| if (resolveResult === undefined) continue | ||
| return resolveResult | ||
| } | ||
| } | ||
| return null | ||
| } | ||
| if (target === null) { | ||
| return null | ||
| } | ||
| throw invalidPackageTarget( | ||
| packageSubpath, | ||
| target, | ||
| packageJsonUrl, | ||
| internal, | ||
| base | ||
| ) | ||
| } | ||
| /** | ||
| * @param {unknown} exports | ||
| * @param {URL} packageJsonUrl | ||
| * @param {URL} base | ||
| * @returns {boolean} | ||
| */ | ||
| function isConditionalExportsMainSugar(exports$1, packageJsonUrl, base) { | ||
| if (typeof exports$1 === 'string' || Array.isArray(exports$1)) return true | ||
| if (typeof exports$1 !== 'object' || exports$1 === null) return false | ||
| const keys = Object.getOwnPropertyNames(exports$1); | ||
| let isConditionalSugar = false; | ||
| let i = 0; | ||
| let keyIndex = -1; | ||
| while (++keyIndex < keys.length) { | ||
| const key = keys[keyIndex]; | ||
| const currentIsConditionalSugar = key === '' || key[0] !== '.'; | ||
| if (i++ === 0) { | ||
| isConditionalSugar = currentIsConditionalSugar; | ||
| } else if (isConditionalSugar !== currentIsConditionalSugar) { | ||
| throw new ERR_INVALID_PACKAGE_CONFIG( | ||
| fileURLToPath$1(packageJsonUrl), | ||
| base, | ||
| '"exports" cannot contain some keys starting with \'.\' and some not.' + | ||
| ' The exports object must either be an object of package subpath keys' + | ||
| ' or an object of main entry condition name keys only.' | ||
| ) | ||
| } | ||
| } | ||
| return isConditionalSugar | ||
| } | ||
| /** | ||
| * @param {string} match | ||
| * @param {URL} pjsonUrl | ||
| * @param {URL} base | ||
| */ | ||
| function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) { | ||
| // @ts-expect-error: apparently it does exist, TS. | ||
| if (process$1.noDeprecation) { | ||
| return | ||
| } | ||
| const pjsonPath = fileURLToPath$1(pjsonUrl); | ||
| if (emittedPackageWarnings.has(pjsonPath + '|' + match)) return | ||
| emittedPackageWarnings.add(pjsonPath + '|' + match); | ||
| process$1.emitWarning( | ||
| `Use of deprecated trailing slash pattern mapping "${match}" in the ` + | ||
| `"exports" field module resolution of the package at ${pjsonPath}${ | ||
| base ? ` imported from ${fileURLToPath$1(base)}` : '' | ||
| }. Mapping specifiers ending in "/" is no longer supported.`, | ||
| 'DeprecationWarning', | ||
| 'DEP0155' | ||
| ); | ||
| } | ||
| /** | ||
| * @param {URL} packageJsonUrl | ||
| * @param {string} packageSubpath | ||
| * @param {Record<string, unknown>} packageConfig | ||
| * @param {URL} base | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL} | ||
| */ | ||
| function packageExportsResolve( | ||
| packageJsonUrl, | ||
| packageSubpath, | ||
| packageConfig, | ||
| base, | ||
| conditions | ||
| ) { | ||
| let exports$1 = packageConfig.exports; | ||
| if (isConditionalExportsMainSugar(exports$1, packageJsonUrl, base)) { | ||
| exports$1 = {'.': exports$1}; | ||
| } | ||
| if ( | ||
| own.call(exports$1, packageSubpath) && | ||
| !packageSubpath.includes('*') && | ||
| !packageSubpath.endsWith('/') | ||
| ) { | ||
| // @ts-expect-error: indexable. | ||
| const target = exports$1[packageSubpath]; | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| '', | ||
| packageSubpath, | ||
| base, | ||
| false, | ||
| false, | ||
| false, | ||
| conditions | ||
| ); | ||
| if (resolveResult === null || resolveResult === undefined) { | ||
| throw exportsNotFound(packageSubpath, packageJsonUrl, base) | ||
| } | ||
| return resolveResult | ||
| } | ||
| let bestMatch = ''; | ||
| let bestMatchSubpath = ''; | ||
| const keys = Object.getOwnPropertyNames(exports$1); | ||
| let i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| const patternIndex = key.indexOf('*'); | ||
| if ( | ||
| patternIndex !== -1 && | ||
| packageSubpath.startsWith(key.slice(0, patternIndex)) | ||
| ) { | ||
| // When this reaches EOL, this can throw at the top of the whole function: | ||
| // | ||
| // if (StringPrototypeEndsWith(packageSubpath, '/')) | ||
| // throwInvalidSubpath(packageSubpath) | ||
| // | ||
| // To match "imports" and the spec. | ||
| if (packageSubpath.endsWith('/')) { | ||
| emitTrailingSlashPatternDeprecation( | ||
| packageSubpath, | ||
| packageJsonUrl, | ||
| base | ||
| ); | ||
| } | ||
| const patternTrailer = key.slice(patternIndex + 1); | ||
| if ( | ||
| packageSubpath.length >= key.length && | ||
| packageSubpath.endsWith(patternTrailer) && | ||
| patternKeyCompare(bestMatch, key) === 1 && | ||
| key.lastIndexOf('*') === patternIndex | ||
| ) { | ||
| bestMatch = key; | ||
| bestMatchSubpath = packageSubpath.slice( | ||
| patternIndex, | ||
| packageSubpath.length - patternTrailer.length | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| if (bestMatch) { | ||
| // @ts-expect-error: indexable. | ||
| const target = /** @type {unknown} */ (exports$1[bestMatch]); | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| bestMatchSubpath, | ||
| bestMatch, | ||
| base, | ||
| true, | ||
| false, | ||
| packageSubpath.endsWith('/'), | ||
| conditions | ||
| ); | ||
| if (resolveResult === null || resolveResult === undefined) { | ||
| throw exportsNotFound(packageSubpath, packageJsonUrl, base) | ||
| } | ||
| return resolveResult | ||
| } | ||
| throw exportsNotFound(packageSubpath, packageJsonUrl, base) | ||
| } | ||
| /** | ||
| * @param {string} a | ||
| * @param {string} b | ||
| */ | ||
| function patternKeyCompare(a, b) { | ||
| const aPatternIndex = a.indexOf('*'); | ||
| const bPatternIndex = b.indexOf('*'); | ||
| const baseLengthA = aPatternIndex === -1 ? a.length : aPatternIndex + 1; | ||
| const baseLengthB = bPatternIndex === -1 ? b.length : bPatternIndex + 1; | ||
| if (baseLengthA > baseLengthB) return -1 | ||
| if (baseLengthB > baseLengthA) return 1 | ||
| if (aPatternIndex === -1) return 1 | ||
| if (bPatternIndex === -1) return -1 | ||
| if (a.length > b.length) return -1 | ||
| if (b.length > a.length) return 1 | ||
| return 0 | ||
| } | ||
| /** | ||
| * @param {string} name | ||
| * @param {URL} base | ||
| * @param {Set<string>} [conditions] | ||
| * @returns {URL} | ||
| */ | ||
| function packageImportsResolve(name, base, conditions) { | ||
| if (name === '#' || name.startsWith('#/') || name.endsWith('/')) { | ||
| const reason = 'is not a valid internal imports specifier name'; | ||
| throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath$1(base)) | ||
| } | ||
| /** @type {URL | undefined} */ | ||
| let packageJsonUrl; | ||
| const packageConfig = getPackageScopeConfig(base); | ||
| if (packageConfig.exists) { | ||
| packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath); | ||
| const imports = packageConfig.imports; | ||
| if (imports) { | ||
| if (own.call(imports, name) && !name.includes('*')) { | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| imports[name], | ||
| '', | ||
| name, | ||
| base, | ||
| false, | ||
| true, | ||
| false, | ||
| conditions | ||
| ); | ||
| if (resolveResult !== null && resolveResult !== undefined) { | ||
| return resolveResult | ||
| } | ||
| } else { | ||
| let bestMatch = ''; | ||
| let bestMatchSubpath = ''; | ||
| const keys = Object.getOwnPropertyNames(imports); | ||
| let i = -1; | ||
| while (++i < keys.length) { | ||
| const key = keys[i]; | ||
| const patternIndex = key.indexOf('*'); | ||
| if (patternIndex !== -1 && name.startsWith(key.slice(0, -1))) { | ||
| const patternTrailer = key.slice(patternIndex + 1); | ||
| if ( | ||
| name.length >= key.length && | ||
| name.endsWith(patternTrailer) && | ||
| patternKeyCompare(bestMatch, key) === 1 && | ||
| key.lastIndexOf('*') === patternIndex | ||
| ) { | ||
| bestMatch = key; | ||
| bestMatchSubpath = name.slice( | ||
| patternIndex, | ||
| name.length - patternTrailer.length | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| if (bestMatch) { | ||
| const target = imports[bestMatch]; | ||
| const resolveResult = resolvePackageTarget( | ||
| packageJsonUrl, | ||
| target, | ||
| bestMatchSubpath, | ||
| bestMatch, | ||
| base, | ||
| true, | ||
| true, | ||
| false, | ||
| conditions | ||
| ); | ||
| if (resolveResult !== null && resolveResult !== undefined) { | ||
| return resolveResult | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| throw importNotDefined(name, packageJsonUrl, base) | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {URL} base | ||
| */ | ||
| function parsePackageName(specifier, base) { | ||
| let separatorIndex = specifier.indexOf('/'); | ||
| let validPackageName = true; | ||
| let isScoped = false; | ||
| if (specifier[0] === '@') { | ||
| isScoped = true; | ||
| if (separatorIndex === -1 || specifier.length === 0) { | ||
| validPackageName = false; | ||
| } else { | ||
| separatorIndex = specifier.indexOf('/', separatorIndex + 1); | ||
| } | ||
| } | ||
| const packageName = | ||
| separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex); | ||
| // Package name cannot have leading . and cannot have percent-encoding or | ||
| // \\ separators. | ||
| if (invalidPackageNameRegEx.exec(packageName) !== null) { | ||
| validPackageName = false; | ||
| } | ||
| if (!validPackageName) { | ||
| throw new ERR_INVALID_MODULE_SPECIFIER( | ||
| specifier, | ||
| 'is not a valid package name', | ||
| fileURLToPath$1(base) | ||
| ) | ||
| } | ||
| const packageSubpath = | ||
| '.' + (separatorIndex === -1 ? '' : specifier.slice(separatorIndex)); | ||
| return {packageName, packageSubpath, isScoped} | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @param {URL} base | ||
| * @param {Set<string> | undefined} conditions | ||
| * @returns {URL} | ||
| */ | ||
| function packageResolve(specifier, base, conditions) { | ||
| if (builtinModules.includes(specifier)) { | ||
| return new URL$1('node:' + specifier) | ||
| } | ||
| const {packageName, packageSubpath, isScoped} = parsePackageName( | ||
| specifier, | ||
| base | ||
| ); | ||
| // ResolveSelf | ||
| const packageConfig = getPackageScopeConfig(base); | ||
| // Can’t test. | ||
| /* c8 ignore next 16 */ | ||
| if (packageConfig.exists) { | ||
| const packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath); | ||
| if ( | ||
| packageConfig.name === packageName && | ||
| packageConfig.exports !== undefined && | ||
| packageConfig.exports !== null | ||
| ) { | ||
| return packageExportsResolve( | ||
| packageJsonUrl, | ||
| packageSubpath, | ||
| packageConfig, | ||
| base, | ||
| conditions | ||
| ) | ||
| } | ||
| } | ||
| let packageJsonUrl = new URL$1( | ||
| './node_modules/' + packageName + '/package.json', | ||
| base | ||
| ); | ||
| let packageJsonPath = fileURLToPath$1(packageJsonUrl); | ||
| /** @type {string} */ | ||
| let lastPath; | ||
| do { | ||
| const stat = tryStatSync(packageJsonPath.slice(0, -13)); | ||
| if (!stat || !stat.isDirectory()) { | ||
| lastPath = packageJsonPath; | ||
| packageJsonUrl = new URL$1( | ||
| (isScoped ? '../../../../node_modules/' : '../../../node_modules/') + | ||
| packageName + | ||
| '/package.json', | ||
| packageJsonUrl | ||
| ); | ||
| packageJsonPath = fileURLToPath$1(packageJsonUrl); | ||
| continue | ||
| } | ||
| // Package match. | ||
| const packageConfig = read(packageJsonPath, {base, specifier}); | ||
| if (packageConfig.exports !== undefined && packageConfig.exports !== null) { | ||
| return packageExportsResolve( | ||
| packageJsonUrl, | ||
| packageSubpath, | ||
| packageConfig, | ||
| base, | ||
| conditions | ||
| ) | ||
| } | ||
| if (packageSubpath === '.') { | ||
| return legacyMainResolve(packageJsonUrl, packageConfig, base) | ||
| } | ||
| return new URL$1(packageSubpath, packageJsonUrl) | ||
| // Cross-platform root check. | ||
| } while (packageJsonPath.length !== lastPath.length) | ||
| throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath$1(base), false) | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @returns {boolean} | ||
| */ | ||
| function isRelativeSpecifier(specifier) { | ||
| if (specifier[0] === '.') { | ||
| if (specifier.length === 1 || specifier[1] === '/') return true | ||
| if ( | ||
| specifier[1] === '.' && | ||
| (specifier.length === 2 || specifier[2] === '/') | ||
| ) { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
| /** | ||
| * @param {string} specifier | ||
| * @returns {boolean} | ||
| */ | ||
| function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) { | ||
| if (specifier === '') return false | ||
| if (specifier[0] === '/') return true | ||
| return isRelativeSpecifier(specifier) | ||
| } | ||
| /** | ||
| * The “Resolver Algorithm Specification” as detailed in the Node docs (which is | ||
| * sync and slightly lower-level than `resolve`). | ||
| * | ||
| * @param {string} specifier | ||
| * `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc. | ||
| * @param {URL} base | ||
| * Full URL (to a file) that `specifier` is resolved relative from. | ||
| * @param {Set<string>} [conditions] | ||
| * Conditions. | ||
| * @param {boolean} [preserveSymlinks] | ||
| * Keep symlinks instead of resolving them. | ||
| * @returns {URL} | ||
| * A URL object to the found thing. | ||
| */ | ||
| function moduleResolve(specifier, base, conditions, preserveSymlinks) { | ||
| // Note: The Node code supports `base` as a string (in this internal API) too, | ||
| // we don’t. | ||
| const protocol = base.protocol; | ||
| const isData = protocol === 'data:'; | ||
| const isRemote = isData || protocol === 'http:' || protocol === 'https:'; | ||
| // Order swapped from spec for minor perf gain. | ||
| // Ok since relative URLs cannot parse as URLs. | ||
| /** @type {URL | undefined} */ | ||
| let resolved; | ||
| if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { | ||
| try { | ||
| resolved = new URL$1(specifier, base); | ||
| } catch (error_) { | ||
| const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base); | ||
| error.cause = error_; | ||
| throw error | ||
| } | ||
| } else if (protocol === 'file:' && specifier[0] === '#') { | ||
| resolved = packageImportsResolve(specifier, base, conditions); | ||
| } else { | ||
| try { | ||
| resolved = new URL$1(specifier); | ||
| } catch (error_) { | ||
| // Note: actual code uses `canBeRequiredWithoutScheme`. | ||
| if (isRemote && !builtinModules.includes(specifier)) { | ||
| const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base); | ||
| error.cause = error_; | ||
| throw error | ||
| } | ||
| resolved = packageResolve(specifier, base, conditions); | ||
| } | ||
| } | ||
| assert(resolved !== undefined, 'expected to be defined'); | ||
| if (resolved.protocol !== 'file:') { | ||
| return resolved | ||
| } | ||
| return finalizeResolution(resolved, base) | ||
| } | ||
| function fileURLToPath(id) { | ||
| if (typeof id === "string" && !id.startsWith("file://")) { | ||
| return normalizeSlash(id); | ||
| } | ||
| return normalizeSlash(fileURLToPath$1(id)); | ||
| } | ||
| function pathToFileURL(id) { | ||
| return pathToFileURL$1(fileURLToPath(id)).toString(); | ||
| } | ||
| function normalizeid(id) { | ||
| if (typeof id !== "string") { | ||
| id = id.toString(); | ||
| } | ||
| if (/(?:node|data|http|https|file):/.test(id)) { | ||
| return id; | ||
| } | ||
| if (BUILTIN_MODULES.has(id)) { | ||
| return "node:" + id; | ||
| } | ||
| return "file://" + encodeURI(normalizeSlash(id)); | ||
| } | ||
| const DEFAULT_CONDITIONS_SET = /* @__PURE__ */ new Set(["node", "import"]); | ||
| const DEFAULT_EXTENSIONS = [".mjs", ".cjs", ".js", ".json"]; | ||
| const NOT_FOUND_ERRORS = /* @__PURE__ */ new Set([ | ||
| "ERR_MODULE_NOT_FOUND", | ||
| "ERR_UNSUPPORTED_DIR_IMPORT", | ||
| "MODULE_NOT_FOUND", | ||
| "ERR_PACKAGE_PATH_NOT_EXPORTED" | ||
| ]); | ||
| function _tryModuleResolve(id, url, conditions) { | ||
| try { | ||
| return moduleResolve(id, url, conditions); | ||
| } catch (error) { | ||
| if (!NOT_FOUND_ERRORS.has(error?.code)) { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
| function _resolve$1(id, options = {}) { | ||
| if (typeof id !== "string") { | ||
| if (id instanceof URL) { | ||
| id = fileURLToPath(id); | ||
| } else { | ||
| throw new TypeError("input must be a `string` or `URL`"); | ||
| } | ||
| } | ||
| if (/(?:node|data|http|https):/.test(id)) { | ||
| return id; | ||
| } | ||
| if (BUILTIN_MODULES.has(id)) { | ||
| return "node:" + id; | ||
| } | ||
| if (id.startsWith("file://")) { | ||
| id = fileURLToPath(id); | ||
| } | ||
| if (isAbsolute(id)) { | ||
| try { | ||
| const stat = statSync(id); | ||
| if (stat.isFile()) { | ||
| return pathToFileURL(id); | ||
| } | ||
| } catch (error) { | ||
| if (error?.code !== "ENOENT") { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
| const conditionsSet = options.conditions ? new Set(options.conditions) : DEFAULT_CONDITIONS_SET; | ||
| const _urls = (Array.isArray(options.url) ? options.url : [options.url]).filter(Boolean).map((url) => new URL(normalizeid(url.toString()))); | ||
| if (_urls.length === 0) { | ||
| _urls.push(new URL(pathToFileURL(process.cwd()))); | ||
| } | ||
| const urls = [..._urls]; | ||
| for (const url of _urls) { | ||
| if (url.protocol === "file:") { | ||
| urls.push( | ||
| new URL("./", url), | ||
| // If url is directory | ||
| new URL(joinURL(url.pathname, "_index.js"), url), | ||
| // TODO: Remove in next major version? | ||
| new URL("node_modules", url) | ||
| ); | ||
| } | ||
| } | ||
| let resolved; | ||
| for (const url of urls) { | ||
| resolved = _tryModuleResolve(id, url, conditionsSet); | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| for (const prefix of ["", "/index"]) { | ||
| for (const extension of options.extensions || DEFAULT_EXTENSIONS) { | ||
| resolved = _tryModuleResolve( | ||
| joinURL(id, prefix) + extension, | ||
| url, | ||
| conditionsSet | ||
| ); | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| } | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| } | ||
| if (resolved) { | ||
| break; | ||
| } | ||
| } | ||
| if (!resolved) { | ||
| const error = new Error( | ||
| `Cannot find module ${id} imported from ${urls.join(", ")}` | ||
| ); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| return pathToFileURL(resolved); | ||
| } | ||
| function resolveSync(id, options) { | ||
| return _resolve$1(id, options); | ||
| } | ||
| function resolvePathSync(id, options) { | ||
| return fileURLToPath(resolveSync(id, options)); | ||
| } | ||
| const GET_IS_ASYNC = Symbol.for("quansync.getIsAsync"); | ||
| class QuansyncError extends Error { | ||
| constructor(message = "Unexpected promise in sync context") { | ||
| super(message); | ||
| this.name = "QuansyncError"; | ||
| } | ||
| } | ||
| function isThenable(value) { | ||
| return value && typeof value === "object" && typeof value.then === "function"; | ||
| } | ||
| function isQuansyncGenerator(value) { | ||
| return value && typeof value === "object" && typeof value[Symbol.iterator] === "function" && "__quansync" in value; | ||
| } | ||
| function fromObject(options) { | ||
| const generator = function* (...args) { | ||
| const isAsync = yield GET_IS_ASYNC; | ||
| if (isAsync) | ||
| return yield options.async.apply(this, args); | ||
| return options.sync.apply(this, args); | ||
| }; | ||
| function fn(...args) { | ||
| const iter = generator.apply(this, args); | ||
| iter.then = (...thenArgs) => options.async.apply(this, args).then(...thenArgs); | ||
| iter.__quansync = true; | ||
| return iter; | ||
| } | ||
| fn.sync = options.sync; | ||
| fn.async = options.async; | ||
| return fn; | ||
| } | ||
| function fromPromise(promise) { | ||
| return fromObject({ | ||
| async: () => Promise.resolve(promise), | ||
| sync: () => { | ||
| if (isThenable(promise)) | ||
| throw new QuansyncError(); | ||
| return promise; | ||
| } | ||
| }); | ||
| } | ||
| function unwrapYield(value, isAsync) { | ||
| if (value === GET_IS_ASYNC) | ||
| return isAsync; | ||
| if (isQuansyncGenerator(value)) | ||
| return isAsync ? iterateAsync(value) : iterateSync(value); | ||
| if (!isAsync && isThenable(value)) | ||
| throw new QuansyncError(); | ||
| return value; | ||
| } | ||
| const DEFAULT_ON_YIELD = (value) => value; | ||
| function iterateSync(generator, onYield = DEFAULT_ON_YIELD) { | ||
| let current = generator.next(); | ||
| while (!current.done) { | ||
| try { | ||
| current = generator.next(unwrapYield(onYield(current.value, false))); | ||
| } catch (err) { | ||
| current = generator.throw(err); | ||
| } | ||
| } | ||
| return unwrapYield(current.value); | ||
| } | ||
| async function iterateAsync(generator, onYield = DEFAULT_ON_YIELD) { | ||
| let current = generator.next(); | ||
| while (!current.done) { | ||
| try { | ||
| current = generator.next(await unwrapYield(onYield(current.value, true), true)); | ||
| } catch (err) { | ||
| current = generator.throw(err); | ||
| } | ||
| } | ||
| return current.value; | ||
| } | ||
| function fromGeneratorFn(generatorFn, options) { | ||
| return fromObject({ | ||
| name: generatorFn.name, | ||
| async(...args) { | ||
| return iterateAsync(generatorFn.apply(this, args), options?.onYield); | ||
| }, | ||
| sync(...args) { | ||
| return iterateSync(generatorFn.apply(this, args), options?.onYield); | ||
| } | ||
| }); | ||
| } | ||
| function quansync$1(input, options) { | ||
| if (isThenable(input)) | ||
| return fromPromise(input); | ||
| if (typeof input === "function") | ||
| return fromGeneratorFn(input, options); | ||
| else | ||
| return fromObject(input); | ||
| } | ||
| quansync$1({ | ||
| async: () => Promise.resolve(true), | ||
| sync: () => false | ||
| }); | ||
| const quansync = quansync$1; | ||
| const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath$1(urlOrPath) : urlOrPath; | ||
| async function findUp$1(name, { | ||
| cwd = process$1.cwd(), | ||
| type = 'file', | ||
| stopAt, | ||
| } = {}) { | ||
| let directory = path.resolve(toPath(cwd) ?? ''); | ||
| const {root} = path.parse(directory); | ||
| stopAt = path.resolve(directory, toPath(stopAt ?? root)); | ||
| const isAbsoluteName = path.isAbsolute(name); | ||
| while (directory) { | ||
| const filePath = isAbsoluteName ? name : path.join(directory, name); | ||
| try { | ||
| const stats = await fs.stat(filePath); // eslint-disable-line no-await-in-loop | ||
| if ((type === 'file' && stats.isFile()) || (type === 'directory' && stats.isDirectory())) { | ||
| return filePath; | ||
| } | ||
| } catch {} | ||
| if (directory === stopAt || directory === root) { | ||
| break; | ||
| } | ||
| directory = path.dirname(directory); | ||
| } | ||
| } | ||
| function findUpSync(name, { | ||
| cwd = process$1.cwd(), | ||
| type = 'file', | ||
| stopAt, | ||
| } = {}) { | ||
| let directory = path.resolve(toPath(cwd) ?? ''); | ||
| const {root} = path.parse(directory); | ||
| stopAt = path.resolve(directory, toPath(stopAt) ?? root); | ||
| const isAbsoluteName = path.isAbsolute(name); | ||
| while (directory) { | ||
| const filePath = isAbsoluteName ? name : path.join(directory, name); | ||
| try { | ||
| const stats = fs__default.statSync(filePath, {throwIfNoEntry: false}); | ||
| if ((type === 'file' && stats?.isFile()) || (type === 'directory' && stats?.isDirectory())) { | ||
| return filePath; | ||
| } | ||
| } catch {} | ||
| if (directory === stopAt || directory === root) { | ||
| break; | ||
| } | ||
| directory = path.dirname(directory); | ||
| } | ||
| } | ||
| function _resolve(path, options = {}) { | ||
| if (options.platform === "auto" || !options.platform) | ||
| options.platform = process$1.platform === "win32" ? "win32" : "posix"; | ||
| if (process$1.versions.pnp) { | ||
| const paths = options.paths || []; | ||
| if (paths.length === 0) | ||
| paths.push(process$1.cwd()); | ||
| const targetRequire = createRequire(import.meta.url); | ||
| try { | ||
| return targetRequire.resolve(path, { paths }); | ||
| } catch { | ||
| } | ||
| } | ||
| const modulePath = resolvePathSync(path, { | ||
| url: options.paths | ||
| }); | ||
| if (options.platform === "win32") | ||
| return win32.normalize(modulePath); | ||
| return modulePath; | ||
| } | ||
| function resolveModule(name, options = {}) { | ||
| try { | ||
| return _resolve(name, options); | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| function isPackageExists(name, options = {}) { | ||
| return !!resolvePackage(name, options); | ||
| } | ||
| function getPackageJsonPath(name, options = {}) { | ||
| const entry = resolvePackage(name, options); | ||
| if (!entry) | ||
| return; | ||
| return searchPackageJSON(entry); | ||
| } | ||
| const readFile = quansync({ | ||
| async: (id) => fs__default.promises.readFile(id, "utf8"), | ||
| sync: (id) => fs__default.readFileSync(id, "utf8") | ||
| }); | ||
| const getPackageInfo = quansync(function* (name, options = {}) { | ||
| const packageJsonPath = getPackageJsonPath(name, options); | ||
| if (!packageJsonPath) | ||
| return; | ||
| const packageJson = JSON.parse(yield readFile(packageJsonPath)); | ||
| return { | ||
| name, | ||
| version: packageJson.version, | ||
| rootPath: dirname(packageJsonPath), | ||
| packageJsonPath, | ||
| packageJson | ||
| }; | ||
| }); | ||
| getPackageInfo.sync; | ||
| function resolvePackage(name, options = {}) { | ||
| try { | ||
| return _resolve(`${name}/package.json`, options); | ||
| } catch { | ||
| } | ||
| try { | ||
| return _resolve(name, options); | ||
| } catch (e) { | ||
| if (e.code !== "MODULE_NOT_FOUND" && e.code !== "ERR_MODULE_NOT_FOUND") | ||
| console.error(e); | ||
| return false; | ||
| } | ||
| } | ||
| function searchPackageJSON(dir) { | ||
| let packageJsonPath; | ||
| while (true) { | ||
| if (!dir) | ||
| return; | ||
| const newDir = dirname(dir); | ||
| if (newDir === dir) | ||
| return; | ||
| dir = newDir; | ||
| packageJsonPath = join(dir, "package.json"); | ||
| if (fs__default.existsSync(packageJsonPath)) | ||
| break; | ||
| } | ||
| return packageJsonPath; | ||
| } | ||
| const findUp = quansync({ | ||
| sync: findUpSync, | ||
| async: findUp$1 | ||
| }); | ||
| const loadPackageJSON = quansync(function* (cwd = process$1.cwd()) { | ||
| const path = yield findUp("package.json", { cwd }); | ||
| if (!path || !fs__default.existsSync(path)) | ||
| return null; | ||
| return JSON.parse(yield readFile(path)); | ||
| }); | ||
| loadPackageJSON.sync; | ||
| const isPackageListed = quansync(function* (name, cwd) { | ||
| const pkg = (yield loadPackageJSON(cwd)) || {}; | ||
| return name in (pkg.dependencies || {}) || name in (pkg.devDependencies || {}); | ||
| }); | ||
| isPackageListed.sync; | ||
| export { isPackageExists as i, resolveModule as r }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| import fs__default from 'node:fs'; | ||
| import { splitFileAndPostfix as splitFileAndPostfix$1, isBareImport } from '@vitest/utils/helpers'; | ||
| import { i as isBuiltin, a as isBrowserExternal, t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { E as EnvironmentTeardownError, a as getSafeWorkerState } from './utils.DYj33du9.js'; | ||
| import { pathToFileURL, URL as URL$1 } from 'node:url'; | ||
| import { normalize, join } from 'pathe'; | ||
| import { distDir } from '../path.js'; | ||
| import { VitestModuleEvaluator, unwrapId } from '../module-evaluator.js'; | ||
| import { isAbsolute, resolve } from 'node:path'; | ||
| import vm from 'node:vm'; | ||
| import { MockerRegistry, mockObject, RedirectedModule, AutomockedModule } from '@vitest/mocker'; | ||
| import { findMockRedirect } from '@vitest/mocker/redirect'; | ||
| import * as viteModuleRunner from 'vite/module-runner'; | ||
| import { Traces } from '../traces.js'; | ||
| import { Console } from 'node:console'; | ||
| class BareModuleMocker { | ||
| static pendingIds = []; | ||
| spyModule; | ||
| primitives; | ||
| registries = /* @__PURE__ */ new Map(); | ||
| mockContext = { callstack: null }; | ||
| _otel; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this._otel = options.traces; | ||
| this.primitives = { | ||
| Object, | ||
| Error, | ||
| Function, | ||
| RegExp, | ||
| Symbol: globalThis.Symbol, | ||
| Array, | ||
| Map | ||
| }; | ||
| if (options.spyModule) this.spyModule = options.spyModule; | ||
| } | ||
| get root() { | ||
| return this.options.root; | ||
| } | ||
| get moduleDirectories() { | ||
| return this.options.moduleDirectories || []; | ||
| } | ||
| getMockerRegistry() { | ||
| const suite = this.getSuiteFilepath(); | ||
| if (!this.registries.has(suite)) this.registries.set(suite, new MockerRegistry()); | ||
| return this.registries.get(suite); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(_id) { | ||
| // implemented by mockers that control the module runner | ||
| } | ||
| isModuleDirectory(path) { | ||
| return this.moduleDirectories.some((dir) => path.includes(dir)); | ||
| } | ||
| getSuiteFilepath() { | ||
| return this.options.getCurrentTestFilepath() || "global"; | ||
| } | ||
| createError(message, codeFrame) { | ||
| const Error = this.primitives.Error; | ||
| const error = new Error(message); | ||
| Object.assign(error, { codeFrame }); | ||
| return error; | ||
| } | ||
| async resolveId(rawId, importer) { | ||
| return this._otel.$("vitest.mocker.resolve_id", { attributes: { | ||
| "vitest.module.raw_id": rawId, | ||
| "vitest.module.importer": rawId | ||
| } }, async (span) => { | ||
| const result = await this.options.resolveId(rawId, importer); | ||
| if (!result) { | ||
| span.addEvent("could not resolve id, fallback to unresolved values"); | ||
| const id = normalizeModuleId(rawId); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": rawId, | ||
| "vitest.module.external": id, | ||
| "vitest.module.fallback": true | ||
| }); | ||
| return { | ||
| id, | ||
| url: rawId, | ||
| external: id | ||
| }; | ||
| } | ||
| // external is node_module or unresolved module | ||
| // for example, some people mock "vscode" and don't have it installed | ||
| const external = !isAbsolute(result.file) || this.isModuleDirectory(result.file) ? normalizeModuleId(rawId) : null; | ||
| const id = normalizeModuleId(result.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": id, | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.external": external ?? false | ||
| }); | ||
| return { | ||
| ...result, | ||
| id, | ||
| external | ||
| }; | ||
| }); | ||
| } | ||
| async resolveMocks() { | ||
| if (!BareModuleMocker.pendingIds.length) return; | ||
| const resolveMock = async (mock) => { | ||
| const { id, url, external } = await this.resolveId(mock.id, mock.importer); | ||
| if (mock.action === "unmock") this.unmockPath(id); | ||
| if (mock.action === "mock") this.mockPath(mock.id, id, url, external, mock.type, mock.factory); | ||
| }; | ||
| // group consecutive mocks of the same action type together, | ||
| // resolve in parallel inside each group, but run groups sequentially | ||
| // to preserve mock/unmock ordering | ||
| const groups = groupByConsecutiveAction(BareModuleMocker.pendingIds); | ||
| for (const group of groups) await Promise.all(group.map(resolveMock)); | ||
| BareModuleMocker.pendingIds = []; | ||
| } | ||
| // public method to avoid circular dependency | ||
| getMockContext() { | ||
| return this.mockContext; | ||
| } | ||
| // path used to store mocked dependencies | ||
| getMockPath(dep) { | ||
| return `mock:${dep}`; | ||
| } | ||
| getDependencyMock(id) { | ||
| return this.getMockerRegistry().getById(fixLeadingSlashes(id)); | ||
| } | ||
| getDependencyMockByUrl(url) { | ||
| return this.getMockerRegistry().get(url); | ||
| } | ||
| findMockRedirect(mockPath, external) { | ||
| return findMockRedirect(this.root, mockPath, external); | ||
| } | ||
| mockObject(object, mockExportsOrModuleType, moduleType) { | ||
| let mockExports; | ||
| if (mockExportsOrModuleType === "automock" || mockExportsOrModuleType === "autospy") { | ||
| moduleType = mockExportsOrModuleType; | ||
| mockExports = void 0; | ||
| } else mockExports = mockExportsOrModuleType; | ||
| moduleType ??= "automock"; | ||
| const createMockInstance = this.spyModule?.createMockInstance; | ||
| if (!createMockInstance) throw this.createError("[vitest] `spyModule` is not defined. This is a Vitest error. Please open a new issue with reproduction."); | ||
| return mockObject({ | ||
| globalConstructors: this.primitives, | ||
| createMockInstance, | ||
| type: moduleType | ||
| }, object, mockExports); | ||
| } | ||
| unmockPath(id) { | ||
| this.getMockerRegistry().deleteById(id); | ||
| this.invalidateModuleById(id); | ||
| } | ||
| mockPath(originalId, id, url, external, mockType, factory) { | ||
| const registry = this.getMockerRegistry(); | ||
| if (mockType === "manual") registry.register("manual", originalId, id, url, factory); | ||
| else if (mockType === "autospy") registry.register("autospy", originalId, id, url); | ||
| else { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) registry.register("redirect", originalId, id, url, redirect); | ||
| else registry.register("automock", originalId, id, url); | ||
| } | ||
| // every time the mock is registered, we remove the previous one from the cache | ||
| this.invalidateModuleById(id); | ||
| } | ||
| async importActual(_rawId, _importer, _callstack) { | ||
| throw new Error(`importActual is not implemented`); | ||
| } | ||
| async importMock(_rawId, _importer, _callstack) { | ||
| throw new Error(`importMock is not implemented`); | ||
| } | ||
| queueMock(id, importer, factoryOrOptions) { | ||
| const mockType = getMockType(factoryOrOptions); | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "mock", | ||
| id, | ||
| importer, | ||
| factory: typeof factoryOrOptions === "function" ? factoryOrOptions : void 0, | ||
| type: mockType | ||
| }); | ||
| } | ||
| queueUnmock(id, importer) { | ||
| BareModuleMocker.pendingIds.push({ | ||
| action: "unmock", | ||
| id, | ||
| importer | ||
| }); | ||
| } | ||
| } | ||
| function getMockType(factoryOrOptions) { | ||
| if (!factoryOrOptions) return "automock"; | ||
| if (typeof factoryOrOptions === "function") return "manual"; | ||
| return factoryOrOptions.spy ? "autospy" : "automock"; | ||
| } | ||
| // unique id that is not available as "$bare_import" like "test" | ||
| // https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix | ||
| const prefixedBuiltins = new Set([ | ||
| "node:sea", | ||
| "node:sqlite", | ||
| "node:test", | ||
| "node:test/reporters" | ||
| ]); | ||
| const isWindows$1 = process.platform === "win32"; | ||
| // transform file url to id | ||
| // virtual:custom -> virtual:custom | ||
| // \0custom -> \0custom | ||
| // /root/id -> /id | ||
| // /root/id.js -> /id.js | ||
| // C:/root/id.js -> /id.js | ||
| // C:\root\id.js -> /id.js | ||
| // TODO: expose this in vite/module-runner | ||
| function normalizeModuleId(file) { | ||
| if (prefixedBuiltins.has(file)) return file; | ||
| // if it's not in the root, keep it as a path, not a URL | ||
| return slash(file).replace(/^\/@fs\//, isWindows$1 ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\//, "/"); | ||
| } | ||
| const windowsSlashRE = /\\/g; | ||
| function slash(p) { | ||
| return p.replace(windowsSlashRE, "/"); | ||
| } | ||
| function groupByConsecutiveAction(mocks) { | ||
| const groups = []; | ||
| for (const mock of mocks) { | ||
| const last = groups.at(-1); | ||
| if (last?.[0].action === mock.action) last.push(mock); | ||
| else groups.push([mock]); | ||
| } | ||
| return groups; | ||
| } | ||
| const multipleSlashRe = /^\/+/; | ||
| // module-runner incorrectly replaces file:///path with `///path` | ||
| function fixLeadingSlashes(id) { | ||
| if (id.startsWith("//")) return id.replace(multipleSlashRe, "/"); | ||
| return id; | ||
| } | ||
| // copied from vite | ||
| // https://github.com/vitejs/vite/blob/4417b4f305623b2850bd6ae6553834c017694672/packages/vite/src/shared/utils.ts | ||
| // https://github.com/vitejs/vite/blob/4417b4f305623b2850bd6ae6553834c017694672/packages/vite/src/node/utils.ts | ||
| const postfixRE = /[?#].*$/; | ||
| const trailingSeparatorRE = /[?&]$/; | ||
| function cleanUrl(url) { | ||
| return url.replace(postfixRE, ""); | ||
| } | ||
| function splitFileAndPostfix(path) { | ||
| const file = cleanUrl(path); | ||
| return { | ||
| file, | ||
| postfix: path.slice(file.length) | ||
| }; | ||
| } | ||
| function injectQuery(url, queryToInject) { | ||
| const { file, postfix } = splitFileAndPostfix(url); | ||
| return `${file}?${queryToInject}${postfix[0] === "?" ? `&${postfix.slice(1)}` : postfix}`; | ||
| } | ||
| function removeQuery(url, queryToRemove) { | ||
| return url.replace(new RegExp(`([?&])${queryToRemove}(?:&|$)`), "$1").replace(trailingSeparatorRE, ""); | ||
| } | ||
| const spyModulePath = resolve(distDir, "spy.js"); | ||
| class VitestMocker extends BareModuleMocker { | ||
| filterPublicKeys; | ||
| constructor(moduleRunner, options) { | ||
| super(options); | ||
| this.moduleRunner = moduleRunner; | ||
| this.options = options; | ||
| const context = this.options.context; | ||
| if (context) this.primitives = vm.runInContext("({ Object, Error, Function, RegExp, Symbol, Array, Map })", context); | ||
| const Symbol = this.primitives.Symbol; | ||
| this.filterPublicKeys = [ | ||
| "__esModule", | ||
| Symbol.asyncIterator, | ||
| Symbol.hasInstance, | ||
| Symbol.isConcatSpreadable, | ||
| Symbol.iterator, | ||
| Symbol.match, | ||
| Symbol.matchAll, | ||
| Symbol.replace, | ||
| Symbol.search, | ||
| Symbol.split, | ||
| Symbol.species, | ||
| Symbol.toPrimitive, | ||
| Symbol.toStringTag, | ||
| Symbol.unscopables | ||
| ]; | ||
| } | ||
| get evaluatedModules() { | ||
| return this.moduleRunner.evaluatedModules; | ||
| } | ||
| async initializeSpyModule() { | ||
| if (this.spyModule) return; | ||
| this.spyModule = await this.moduleRunner.import(spyModulePath); | ||
| } | ||
| reset() { | ||
| this.registries.clear(); | ||
| } | ||
| invalidateModuleById(id) { | ||
| const mockId = this.getMockPath(id); | ||
| const node = this.evaluatedModules.getModuleById(mockId); | ||
| if (node) { | ||
| this.evaluatedModules.invalidateModule(node); | ||
| node.mockedExports = void 0; | ||
| } | ||
| } | ||
| ensureModule(id, url) { | ||
| const node = this.evaluatedModules.ensureModule(id, url); | ||
| // TODO | ||
| node.meta = { | ||
| id, | ||
| url, | ||
| code: "", | ||
| file: null, | ||
| invalidate: false | ||
| }; | ||
| return node; | ||
| } | ||
| async callFunctionMock(id, url, mock) { | ||
| const node = this.ensureModule(id, url); | ||
| if (node.exports) return node.exports; | ||
| const exports$1 = await mock.resolve(); | ||
| const moduleExports = new Proxy(exports$1, { get: (target, prop) => { | ||
| const val = target[prop]; | ||
| // 'then' can exist on non-Promise objects, need nested instanceof check for logic to work | ||
| if (prop === "then") { | ||
| if (target instanceof Promise) return target.then.bind(target); | ||
| } else if (!(prop in target)) { | ||
| if (this.filterPublicKeys.includes(prop)) return; | ||
| throw this.createError(`[vitest] No "${String(prop)}" export is defined on the "${mock.raw}" mock. Did you forget to return it from "vi.mock"? | ||
| If you need to partially mock a module, you can use "importOriginal" helper inside: | ||
| `, `vi.mock(import("${mock.raw}"), async (importOriginal) => { | ||
| const actual = await importOriginal() | ||
| return { | ||
| ...actual, | ||
| // your mocked methods | ||
| } | ||
| })`); | ||
| } | ||
| return val; | ||
| } }); | ||
| node.exports = moduleExports; | ||
| return moduleExports; | ||
| } | ||
| async importActual(rawId, importer, callstack) { | ||
| const { url } = await this.resolveId(rawId, importer); | ||
| const actualUrl = injectQuery(url, "_vitest_original"); | ||
| const node = await this.moduleRunner.fetchModule(actualUrl, importer); | ||
| return await this.moduleRunner.cachedRequest(node.url, node, callstack || [importer], void 0, true); | ||
| } | ||
| async importMock(rawId, importer) { | ||
| const { id, url, external } = await this.resolveId(rawId, importer); | ||
| let mock = this.getDependencyMock(id); | ||
| if (!mock) { | ||
| const redirect = this.findMockRedirect(id, external); | ||
| if (redirect) mock = new RedirectedModule(rawId, id, rawId, redirect); | ||
| else mock = new AutomockedModule(rawId, id, rawId); | ||
| } | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const node = await this.moduleRunner.fetchModule(url, importer); | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, [importer], void 0, true); | ||
| const Object = this.primitives.Object; | ||
| return this.mockObject(mod, Object.create(Object.prototype), mock.type); | ||
| } | ||
| if (mock.type === "manual") return this.callFunctionMock(id, url, mock); | ||
| const node = await this.moduleRunner.fetchModule(mock.redirect); | ||
| return this.moduleRunner.cachedRequest(mock.redirect, node, [importer], void 0, true); | ||
| } | ||
| async requestWithMockedModule(url, evaluatedNode, callstack, mock) { | ||
| return this._otel.$("vitest.mocker.evaluate", async (span) => { | ||
| const mockId = this.getMockPath(evaluatedNode.id); | ||
| span.setAttributes({ | ||
| "vitest.module.id": mockId, | ||
| "vitest.mock.type": mock.type, | ||
| "vitest.mock.id": mock.id, | ||
| "vitest.mock.url": mock.url, | ||
| "vitest.mock.raw": mock.raw | ||
| }); | ||
| if (mock.type === "automock" || mock.type === "autospy") { | ||
| const cache = this.evaluatedModules.getModuleById(mockId); | ||
| if (cache && cache.mockedExports) return cache.mockedExports; | ||
| const Object = this.primitives.Object; | ||
| // we have to define a separate object that will copy all properties into itself | ||
| // and can't just use the same `exports` define automatically by Vite before the evaluator | ||
| const exports$1 = Object.create(null); | ||
| Object.defineProperty(exports$1, Symbol.toStringTag, { | ||
| value: "Module", | ||
| configurable: true, | ||
| writable: true | ||
| }); | ||
| const node = this.ensureModule(mockId, this.getMockPath(evaluatedNode.url)); | ||
| node.meta = evaluatedNode.meta; | ||
| node.file = evaluatedNode.file; | ||
| node.mockedExports = exports$1; | ||
| const mod = await this.moduleRunner.cachedRequest(url, node, callstack, void 0, true); | ||
| this.mockObject(mod, exports$1, mock.type); | ||
| return exports$1; | ||
| } | ||
| if (mock.type === "manual" && !callstack.includes(mockId) && !callstack.includes(url)) try { | ||
| callstack.push(mockId); | ||
| // this will not work if user does Promise.all(import(), import()) | ||
| // we can also use AsyncLocalStorage to store callstack, but this won't work in the browser | ||
| // maybe we should improve mock API in the future? | ||
| this.mockContext.callstack = callstack; | ||
| return await this.callFunctionMock(mockId, this.getMockPath(url), mock); | ||
| } finally { | ||
| this.mockContext.callstack = null; | ||
| const indexMock = callstack.indexOf(mockId); | ||
| callstack.splice(indexMock, 1); | ||
| } | ||
| else if (mock.type === "redirect" && !callstack.includes(mock.redirect)) { | ||
| span.setAttribute("vitest.mock.redirect", mock.redirect); | ||
| return mock.redirect; | ||
| } | ||
| }); | ||
| } | ||
| async mockedRequest(url, evaluatedNode, callstack) { | ||
| const mock = this.getDependencyMock(evaluatedNode.id); | ||
| if (!mock) return; | ||
| return this.requestWithMockedModule(url, evaluatedNode, callstack, mock); | ||
| } | ||
| } | ||
| class VitestTransport { | ||
| constructor(options, evaluatedModules, callstacks) { | ||
| this.options = options; | ||
| this.evaluatedModules = evaluatedModules; | ||
| this.callstacks = callstacks; | ||
| } | ||
| async invoke(event) { | ||
| if (event.type !== "custom") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support Vite HMR events.`) }; | ||
| if (event.event !== "vite:invoke") return { error: /* @__PURE__ */ new Error(`Vitest Module Runner doesn't support ${event.event} event.`) }; | ||
| const { name, data } = event.data; | ||
| if (name === "getBuiltins") | ||
| // we return an empty array here to avoid client-side builtin check, | ||
| // as we need builtins to go through `fetchModule` | ||
| return { result: [] }; | ||
| if (name !== "fetchModule") return { error: /* @__PURE__ */ new Error(`Unknown method: ${name}. Expected "fetchModule".`) }; | ||
| try { | ||
| return { result: await this.options.fetchModule(...data) }; | ||
| } catch (cause) { | ||
| if (cause instanceof EnvironmentTeardownError) { | ||
| const [id, importer] = data; | ||
| let message = `Cannot load '${id}'${importer ? ` imported from ${importer}` : ""} after the environment was torn down. This is not a bug in Vitest.`; | ||
| const moduleNode = importer ? this.evaluatedModules.getModuleById(importer) : void 0; | ||
| const callstack = moduleNode ? this.callstacks.get(moduleNode) : void 0; | ||
| if (callstack) message += ` The last recorded callstack:\n- ${[ | ||
| ...callstack, | ||
| importer, | ||
| id | ||
| ].reverse().join("\n- ")}`; | ||
| const error = new EnvironmentTeardownError(message); | ||
| if (cause.stack) error.stack = cause.stack.replace(cause.message, error.message); | ||
| return { error }; | ||
| } | ||
| return { error: cause }; | ||
| } | ||
| } | ||
| } | ||
| const createNodeImportMeta = (modulePath) => { | ||
| if (!viteModuleRunner.createDefaultImportMeta) throw new Error(`createNodeImportMeta is not supported in this version of Vite.`); | ||
| const defaultMeta = viteModuleRunner.createDefaultImportMeta(modulePath); | ||
| const href = defaultMeta.url; | ||
| const importMetaResolver = createImportMetaResolver(); | ||
| return { | ||
| ...defaultMeta, | ||
| main: false, | ||
| resolve(id, parent) { | ||
| return (importMetaResolver ?? defaultMeta.resolve)(id, parent ?? href); | ||
| } | ||
| }; | ||
| }; | ||
| function createImportMetaResolver() { | ||
| if (!import.meta.resolve) return; | ||
| return (specifier, importer) => import.meta.resolve(specifier, importer); | ||
| } | ||
| // @ts-expect-error overriding private method | ||
| class VitestModuleRunner extends viteModuleRunner.ModuleRunner { | ||
| mocker; | ||
| moduleExecutionInfo; | ||
| _otel; | ||
| _callstacks; | ||
| constructor(vitestOptions) { | ||
| const options = vitestOptions; | ||
| const evaluatedModules = options.evaluatedModules; | ||
| const callstacks = /* @__PURE__ */ new WeakMap(); | ||
| const transport = new VitestTransport(options.transport, evaluatedModules, callstacks); | ||
| super({ | ||
| transport, | ||
| hmr: false, | ||
| evaluatedModules, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| createImportMeta: vitestOptions.createImportMeta | ||
| }, options.evaluator); | ||
| this.vitestOptions = vitestOptions; | ||
| this._callstacks = callstacks; | ||
| this._otel = vitestOptions.traces || new Traces({ enabled: false }); | ||
| this.moduleExecutionInfo = options.getWorkerState().moduleExecutionInfo; | ||
| this.mocker = options.mocker || new VitestMocker(this, { | ||
| spyModule: options.spyModule, | ||
| context: options.vm?.context, | ||
| traces: this._otel, | ||
| resolveId: options.transport.resolveId, | ||
| get root() { | ||
| return options.getWorkerState().config.root; | ||
| }, | ||
| get moduleDirectories() { | ||
| return options.getWorkerState().config.deps.moduleDirectories || []; | ||
| }, | ||
| getCurrentTestFilepath() { | ||
| return options.getWorkerState().filepath; | ||
| } | ||
| }); | ||
| if (options.vm) options.vm.context.__vitest_mocker__ = this.mocker; | ||
| else Object.defineProperty(globalThis, "__vitest_mocker__", { | ||
| configurable: true, | ||
| writable: true, | ||
| value: this.mocker | ||
| }); | ||
| } | ||
| /** | ||
| * Vite checks that the module has exports emulating the Node.js behaviour, | ||
| * but Vitest is more relaxed. | ||
| * | ||
| * We should keep the Vite behavior when there is a `strict` flag. | ||
| * @internal | ||
| */ | ||
| processImport(exports$1) { | ||
| return exports$1; | ||
| } | ||
| async import(rawId) { | ||
| const resolved = await this._otel.$("vitest.module.resolve_id", { attributes: { "vitest.module.raw_id": rawId } }, async (span) => { | ||
| const result = await this.vitestOptions.transport.resolveId(rawId); | ||
| if (result) span.setAttributes({ | ||
| "vitest.module.url": result.url, | ||
| "vitest.module.file": result.file, | ||
| "vitest.module.id": result.id | ||
| }); | ||
| return result; | ||
| }); | ||
| return super.import(resolved ? resolved.url : rawId); | ||
| } | ||
| async fetchModule(url, importer) { | ||
| return await this.cachedModule(url, importer); | ||
| } | ||
| _cachedRequest(url, module, callstack = [], metadata) { | ||
| // @ts-expect-error "cachedRequest" is private | ||
| return super.cachedRequest(url, module, callstack, metadata); | ||
| } | ||
| /** | ||
| * @internal | ||
| */ | ||
| async cachedRequest(url, mod, callstack = [], metadata, ignoreMock = false) { | ||
| // Track for a better error message if dynamic import is not resolved properly | ||
| this._callstacks.set(mod, callstack); | ||
| if (ignoreMock) return this._cachedRequest(url, mod, callstack, metadata); | ||
| let mocked; | ||
| if (mod.meta && "mockedModule" in mod.meta) { | ||
| const mockedModule = mod.meta.mockedModule; | ||
| const mockId = this.mocker.getMockPath(mod.id); | ||
| // bypass mock and force "importActual" behavior when: | ||
| // - mock was removed by doUnmock (stale mockedModule in meta) | ||
| // - self-import: mock factory/file is importing the module it's mocking | ||
| const isStale = !this.mocker.getDependencyMock(mod.id); | ||
| const isSelfImport = callstack.includes(mockId) || callstack.includes(url) || "redirect" in mockedModule && callstack.includes(mockedModule.redirect); | ||
| if (isStale || isSelfImport) { | ||
| const node = await this.fetchModule(injectQuery(url, "_vitest_original")); | ||
| return this._cachedRequest(node.url, node, callstack, metadata); | ||
| } | ||
| mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, mockedModule); | ||
| } else mocked = await this.mocker.mockedRequest(url, mod, callstack); | ||
| if (typeof mocked === "string") { | ||
| const node = await this.fetchModule(mocked); | ||
| return this._cachedRequest(mocked, node, callstack, metadata); | ||
| } | ||
| if (mocked != null && typeof mocked === "object") return mocked; | ||
| return this._cachedRequest(url, mod, callstack, metadata); | ||
| } | ||
| /** @internal */ | ||
| _invalidateSubTreeById(ids, invalidated = /* @__PURE__ */ new Set()) { | ||
| for (const id of ids) { | ||
| if (invalidated.has(id)) continue; | ||
| const node = this.evaluatedModules.getModuleById(id); | ||
| if (!node) continue; | ||
| invalidated.add(id); | ||
| const subIds = Array.from(this.evaluatedModules.idToModuleMap).filter(([, mod]) => mod.importers.has(id)).map(([key]) => key); | ||
| if (subIds.length) this._invalidateSubTreeById(subIds, invalidated); | ||
| this.evaluatedModules.invalidateModule(node); | ||
| } | ||
| } | ||
| } | ||
| const bareVitestRegexp = /^@?vitest(?:\/|$)/; | ||
| const normalizedDistDir = normalize(distDir); | ||
| const relativeIds = {}; | ||
| const externalizeMap = /* @__PURE__ */ new Map(); | ||
| // all Vitest imports always need to be externalized | ||
| function getCachedVitestImport(id, state) { | ||
| if (id.startsWith("/@fs/") || id.startsWith("\\@fs\\")) id = id.slice(process.platform === "win32" ? 5 : 4); | ||
| if (externalizeMap.has(id)) return { | ||
| externalize: externalizeMap.get(id), | ||
| type: "module" | ||
| }; | ||
| // always externalize Vitest because we import from there before running tests | ||
| // so we already have it cached by Node.js | ||
| const root = state().config.root; | ||
| const relativeRoot = relativeIds[root] ?? (relativeIds[root] = normalizedDistDir.slice(root.length)); | ||
| if (id.includes(distDir) || id.includes(normalizedDistDir)) { | ||
| const { file, postfix } = splitFileAndPostfix$1(id); | ||
| const externalize = id.startsWith("file://") ? id : `${pathToFileURL(file)}${postfix}`; | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (relativeRoot && relativeRoot !== "/" && id.startsWith(relativeRoot)) { | ||
| const { file, postfix } = splitFileAndPostfix$1(id); | ||
| const externalize = `${pathToFileURL(join(root, file))}${postfix}`; | ||
| externalizeMap.set(id, externalize); | ||
| return { | ||
| externalize, | ||
| type: "module" | ||
| }; | ||
| } | ||
| if (bareVitestRegexp.test(id)) { | ||
| externalizeMap.set(id, id); | ||
| return { | ||
| externalize: id, | ||
| type: "module" | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| const { readFileSync } = fs__default; | ||
| const VITEST_VM_CONTEXT_SYMBOL = "__vitest_vm_context__"; | ||
| const cwd = process.cwd(); | ||
| const isWindows = process.platform === "win32"; | ||
| function startVitestModuleRunner(options) { | ||
| const traces = options.traces; | ||
| const state = () => getSafeWorkerState() || options.state; | ||
| const rpc = () => state().rpc; | ||
| const environment = () => { | ||
| const environment = state().environment; | ||
| return environment.viteEnvironment || environment.name; | ||
| }; | ||
| const vm = options.context && options.externalModulesExecutor ? { | ||
| context: options.context, | ||
| externalModulesExecutor: options.externalModulesExecutor | ||
| } : void 0; | ||
| const evaluator = options.evaluator || new VitestModuleEvaluator(vm, { | ||
| traces, | ||
| evaluatedModules: options.evaluatedModules, | ||
| get moduleExecutionInfo() { | ||
| return state().moduleExecutionInfo; | ||
| }, | ||
| get interopDefault() { | ||
| return state().config.deps.interopDefault; | ||
| }, | ||
| getCurrentTestFilepath: () => state().filepath, | ||
| getterTracker: state().getterTracker | ||
| }); | ||
| const moduleRunner = new VitestModuleRunner({ | ||
| spyModule: options.spyModule, | ||
| evaluatedModules: options.evaluatedModules, | ||
| evaluator, | ||
| traces, | ||
| mocker: options.mocker, | ||
| transport: { | ||
| async fetchModule(id, importer, options) { | ||
| const resolvingModules = state().resolvingModules; | ||
| if (isWindows) { | ||
| if (id[1] === ":") { | ||
| // The drive letter is different for whatever reason, we need to normalize it to CWD | ||
| if (id[0] !== cwd[0] && id[0].toUpperCase() === cwd[0].toUpperCase()) id = (cwd[0].toUpperCase() === cwd[0] ? id[0].toUpperCase() : id[0].toLowerCase()) + id.slice(1); | ||
| // always mark absolute windows paths, otherwise Vite will externalize it | ||
| id = `/@id/${id}`; | ||
| } | ||
| } | ||
| const vitest = getCachedVitestImport(id, state); | ||
| if (vitest) return vitest; | ||
| // strip _vitest_original query added by importActual so that | ||
| // the plugin pipeline sees the original import id (e.g. virtual modules's load hook) | ||
| const isImportActual = id.includes("_vitest_original"); | ||
| if (isImportActual) id = removeQuery(id, "_vitest_original"); | ||
| const rawId = unwrapId(id); | ||
| resolvingModules.add(rawId); | ||
| try { | ||
| if (VitestMocker.pendingIds.length) await moduleRunner.mocker.resolveMocks(); | ||
| if (!isImportActual) { | ||
| const resolvedMock = moduleRunner.mocker.getDependencyMockByUrl(id); | ||
| if (resolvedMock?.type === "manual" || resolvedMock?.type === "redirect") return { | ||
| code: "", | ||
| file: null, | ||
| id: resolvedMock.id, | ||
| url: resolvedMock.url, | ||
| invalidate: false, | ||
| mockedModule: resolvedMock | ||
| }; | ||
| } | ||
| if (isBuiltin(rawId)) return { | ||
| externalize: rawId, | ||
| type: "builtin" | ||
| }; | ||
| if (isBrowserExternal(rawId)) return { | ||
| externalize: toBuiltin(rawId), | ||
| type: "builtin" | ||
| }; | ||
| // if module is invalidated, the worker will be recreated, | ||
| // so cached is always true in a single worker | ||
| if (!isImportActual && options?.cached) return { cache: true }; | ||
| const otelCarrier = traces?.getContextCarrier(); | ||
| const result = await rpc().fetch(id, importer, environment(), options, otelCarrier); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| return result; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause != null && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url") || typeof cause?.message === "string" && cause.message.startsWith("Cannot find module '")) { | ||
| const error = new Error(`Cannot find ${isBareImport(id) ? "package" : "module"} '${id}'${importer ? ` imported from ${importer}` : ""}`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| throw cause; | ||
| } finally { | ||
| resolvingModules.delete(rawId); | ||
| } | ||
| }, | ||
| resolveId(id, importer) { | ||
| return rpc().resolve(id, importer, environment()); | ||
| } | ||
| }, | ||
| getWorkerState: state, | ||
| vm, | ||
| createImportMeta: options.createImportMeta | ||
| }); | ||
| return moduleRunner; | ||
| } | ||
| // SEE https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/interfaces.js | ||
| const LIVING_KEYS = [ | ||
| "DOMException", | ||
| "EventTarget", | ||
| "NamedNodeMap", | ||
| "Node", | ||
| "Attr", | ||
| "Element", | ||
| "DocumentFragment", | ||
| "DOMImplementation", | ||
| "Document", | ||
| "XMLDocument", | ||
| "CharacterData", | ||
| "Text", | ||
| "CDATASection", | ||
| "ProcessingInstruction", | ||
| "Comment", | ||
| "DocumentType", | ||
| "NodeList", | ||
| "RadioNodeList", | ||
| "HTMLCollection", | ||
| "HTMLOptionsCollection", | ||
| "DOMStringMap", | ||
| "DOMTokenList", | ||
| "StyleSheetList", | ||
| "HTMLElement", | ||
| "HTMLHeadElement", | ||
| "HTMLTitleElement", | ||
| "HTMLBaseElement", | ||
| "HTMLLinkElement", | ||
| "HTMLMetaElement", | ||
| "HTMLStyleElement", | ||
| "HTMLBodyElement", | ||
| "HTMLHeadingElement", | ||
| "HTMLParagraphElement", | ||
| "HTMLHRElement", | ||
| "HTMLPreElement", | ||
| "HTMLUListElement", | ||
| "HTMLOListElement", | ||
| "HTMLLIElement", | ||
| "HTMLMenuElement", | ||
| "HTMLDListElement", | ||
| "HTMLDivElement", | ||
| "HTMLAnchorElement", | ||
| "HTMLAreaElement", | ||
| "HTMLBRElement", | ||
| "HTMLButtonElement", | ||
| "HTMLCanvasElement", | ||
| "HTMLDataElement", | ||
| "HTMLDataListElement", | ||
| "HTMLDetailsElement", | ||
| "HTMLDialogElement", | ||
| "HTMLDirectoryElement", | ||
| "HTMLFieldSetElement", | ||
| "HTMLFontElement", | ||
| "HTMLFormElement", | ||
| "HTMLHtmlElement", | ||
| "HTMLImageElement", | ||
| "HTMLInputElement", | ||
| "HTMLLabelElement", | ||
| "HTMLLegendElement", | ||
| "HTMLMapElement", | ||
| "HTMLMarqueeElement", | ||
| "HTMLMediaElement", | ||
| "HTMLMeterElement", | ||
| "HTMLModElement", | ||
| "HTMLOptGroupElement", | ||
| "HTMLOptionElement", | ||
| "HTMLOutputElement", | ||
| "HTMLPictureElement", | ||
| "HTMLProgressElement", | ||
| "HTMLQuoteElement", | ||
| "HTMLScriptElement", | ||
| "HTMLSelectElement", | ||
| "HTMLSlotElement", | ||
| "HTMLSourceElement", | ||
| "HTMLSpanElement", | ||
| "HTMLTableCaptionElement", | ||
| "HTMLTableCellElement", | ||
| "HTMLTableColElement", | ||
| "HTMLTableElement", | ||
| "HTMLTimeElement", | ||
| "HTMLTableRowElement", | ||
| "HTMLTableSectionElement", | ||
| "HTMLTemplateElement", | ||
| "HTMLTextAreaElement", | ||
| "HTMLUnknownElement", | ||
| "HTMLFrameElement", | ||
| "HTMLFrameSetElement", | ||
| "HTMLIFrameElement", | ||
| "HTMLEmbedElement", | ||
| "HTMLObjectElement", | ||
| "HTMLParamElement", | ||
| "HTMLVideoElement", | ||
| "HTMLAudioElement", | ||
| "HTMLTrackElement", | ||
| "HTMLFormControlsCollection", | ||
| "SVGElement", | ||
| "SVGGraphicsElement", | ||
| "SVGSVGElement", | ||
| "SVGTitleElement", | ||
| "SVGAnimatedString", | ||
| "SVGNumber", | ||
| "SVGStringList", | ||
| "Event", | ||
| "CloseEvent", | ||
| "CustomEvent", | ||
| "MessageEvent", | ||
| "ErrorEvent", | ||
| "HashChangeEvent", | ||
| "PopStateEvent", | ||
| "StorageEvent", | ||
| "ProgressEvent", | ||
| "PageTransitionEvent", | ||
| "SubmitEvent", | ||
| "UIEvent", | ||
| "FocusEvent", | ||
| "InputEvent", | ||
| "MouseEvent", | ||
| "KeyboardEvent", | ||
| "TouchEvent", | ||
| "CompositionEvent", | ||
| "WheelEvent", | ||
| "BarProp", | ||
| "External", | ||
| "Location", | ||
| "History", | ||
| "Screen", | ||
| "Crypto", | ||
| "Performance", | ||
| "Navigator", | ||
| "PluginArray", | ||
| "MimeTypeArray", | ||
| "Plugin", | ||
| "MimeType", | ||
| "FileReader", | ||
| "FormData", | ||
| "Blob", | ||
| "File", | ||
| "FileList", | ||
| "ValidityState", | ||
| "DOMParser", | ||
| "XMLSerializer", | ||
| "XMLHttpRequestEventTarget", | ||
| "XMLHttpRequestUpload", | ||
| "XMLHttpRequest", | ||
| "WebSocket", | ||
| "NodeFilter", | ||
| "NodeIterator", | ||
| "TreeWalker", | ||
| "AbstractRange", | ||
| "Range", | ||
| "StaticRange", | ||
| "Selection", | ||
| "Storage", | ||
| "CustomElementRegistry", | ||
| "ShadowRoot", | ||
| "MutationObserver", | ||
| "MutationRecord", | ||
| "Uint8Array", | ||
| "Uint16Array", | ||
| "Uint32Array", | ||
| "Uint8ClampedArray", | ||
| "Int8Array", | ||
| "Int16Array", | ||
| "Int32Array", | ||
| "Float32Array", | ||
| "Float64Array", | ||
| "ArrayBuffer", | ||
| "DOMRectReadOnly", | ||
| "DOMRect", | ||
| "Image", | ||
| "Audio", | ||
| "Option", | ||
| "CSS" | ||
| ]; | ||
| const OTHER_KEYS = [ | ||
| "addEventListener", | ||
| "alert", | ||
| "blur", | ||
| "cancelAnimationFrame", | ||
| "close", | ||
| "confirm", | ||
| "createPopup", | ||
| "dispatchEvent", | ||
| "document", | ||
| "focus", | ||
| "frames", | ||
| "getComputedStyle", | ||
| "history", | ||
| "innerHeight", | ||
| "innerWidth", | ||
| "length", | ||
| "localStorage", | ||
| "location", | ||
| "matchMedia", | ||
| "moveBy", | ||
| "moveTo", | ||
| "name", | ||
| "navigator", | ||
| "open", | ||
| "outerHeight", | ||
| "outerWidth", | ||
| "pageXOffset", | ||
| "pageYOffset", | ||
| "parent", | ||
| "postMessage", | ||
| "print", | ||
| "prompt", | ||
| "removeEventListener", | ||
| "requestAnimationFrame", | ||
| "resizeBy", | ||
| "resizeTo", | ||
| "screen", | ||
| "screenLeft", | ||
| "screenTop", | ||
| "screenX", | ||
| "screenY", | ||
| "scroll", | ||
| "scrollBy", | ||
| "scrollLeft", | ||
| "scrollTo", | ||
| "scrollTop", | ||
| "scrollX", | ||
| "scrollY", | ||
| "self", | ||
| "sessionStorage", | ||
| "stop", | ||
| "top", | ||
| "Window", | ||
| "window" | ||
| ]; | ||
| const KEYS = LIVING_KEYS.concat(OTHER_KEYS); | ||
| const skipKeys = [ | ||
| "window", | ||
| "self", | ||
| "top", | ||
| "parent" | ||
| ]; | ||
| function getWindowKeys(global, win, additionalKeys = []) { | ||
| const keysArray = [...additionalKeys, ...KEYS]; | ||
| return new Set(keysArray.concat(Object.getOwnPropertyNames(win)).filter((k) => { | ||
| if (skipKeys.includes(k)) return false; | ||
| if (k in global) return keysArray.includes(k); | ||
| return true; | ||
| })); | ||
| } | ||
| function isClassLikeName(name) { | ||
| return name[0] === name[0].toUpperCase(); | ||
| } | ||
| function populateGlobal(global, win, options = {}) { | ||
| const { bindFunctions = false } = options; | ||
| const keys = getWindowKeys(global, win, options.additionalKeys); | ||
| const originals = /* @__PURE__ */ new Map(); | ||
| const overriddenKeys = new Set([...KEYS, ...options.additionalKeys || []]); | ||
| const overrideObject = /* @__PURE__ */ new Map(); | ||
| for (const key of keys) { | ||
| const boundFunction = bindFunctions && typeof win[key] === "function" && !isClassLikeName(key) && win[key].bind(win); | ||
| if (overriddenKeys.has(key) && key in global) { | ||
| // capture the descriptor instead of the value to avoid invoking native | ||
| // lazy getters such as Node's `localStorage`, which warns when accessed | ||
| // without `--localstorage-file` | ||
| const descriptor = Object.getOwnPropertyDescriptor(global, key) ?? { | ||
| value: global[key], | ||
| configurable: true, | ||
| writable: true, | ||
| enumerable: true | ||
| }; | ||
| originals.set(key, descriptor); | ||
| } | ||
| Object.defineProperty(global, key, { | ||
| get() { | ||
| if (overrideObject.has(key)) return overrideObject.get(key); | ||
| if (boundFunction) return boundFunction; | ||
| return win[key]; | ||
| }, | ||
| set(v) { | ||
| overrideObject.set(key, v); | ||
| // propagate changes to underlying window implementation, | ||
| // which can affect other window API behavior internally, e.g. | ||
| // updating `innerWidth` affects `matchMedia("(max-width: *)")` on happy-dom. | ||
| win[key] = v; | ||
| }, | ||
| configurable: true | ||
| }); | ||
| } | ||
| global.window = global; | ||
| global.self = global; | ||
| global.top = global; | ||
| global.parent = global; | ||
| if (global.global) global.global = global; | ||
| // rewrite defaultView to reference the same global context | ||
| if (global.document && global.document.defaultView) Object.defineProperty(global.document, "defaultView", { | ||
| get: () => global, | ||
| enumerable: true, | ||
| configurable: true | ||
| }); | ||
| skipKeys.forEach((k) => keys.add(k)); | ||
| return { | ||
| keys, | ||
| skipKeys, | ||
| originals | ||
| }; | ||
| } | ||
| var edge = { | ||
| name: "edge-runtime", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const vm = new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| return context; | ||
| } }); | ||
| return { | ||
| getVmContext() { | ||
| return vm.context; | ||
| }, | ||
| teardown() { | ||
| // nothing to teardown | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| const { EdgeVM } = await import('@edge-runtime/vm'); | ||
| const { keys, originals } = populateGlobal(global, new EdgeVM({ extend: (context) => { | ||
| context.global = context; | ||
| context.Buffer = Buffer; | ||
| KEYS.forEach((key) => { | ||
| if (key in global) context[key] = global[key]; | ||
| }); | ||
| return context; | ||
| } }).context, { bindFunctions: true }); | ||
| return { teardown(global) { | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((d, k) => Object.defineProperty(global, k, d)); | ||
| } }; | ||
| } | ||
| }; | ||
| async function teardownWindow(win) { | ||
| if (win.close && win.happyDOM.abort) { | ||
| await win.happyDOM.abort(); | ||
| win.close(); | ||
| } else win.happyDOM.cancelAsync(); | ||
| } | ||
| var happy = { | ||
| name: "happy-dom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ happyDOM = {} }) { | ||
| const { Window } = await import('happy-dom'); | ||
| let win = new Window({ | ||
| ...happyDOM, | ||
| console: console && globalThis.console ? globalThis.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| win.Buffer = Buffer; | ||
| // inject structuredClone if it exists | ||
| if (typeof structuredClone !== "undefined" && !win.structuredClone) win.structuredClone = structuredClone; | ||
| return { | ||
| getVmContext() { | ||
| return win; | ||
| }, | ||
| async teardown() { | ||
| await teardownWindow(win); | ||
| win = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { happyDOM = {} }) { | ||
| // happy-dom v3 introduced a breaking change to Window, but | ||
| // provides GlobalWindow as a way to use previous behaviour | ||
| const { Window, GlobalWindow } = await import('happy-dom'); | ||
| const win = new (GlobalWindow || Window)({ | ||
| ...happyDOM, | ||
| console: console && global.console ? global.console : void 0, | ||
| url: happyDOM.url || "http://localhost:3000", | ||
| settings: { | ||
| ...happyDOM.settings, | ||
| disableErrorCapturing: true | ||
| } | ||
| }); | ||
| const { keys, originals } = populateGlobal(global, win, { | ||
| bindFunctions: true, | ||
| additionalKeys: [ | ||
| "Request", | ||
| "Response", | ||
| "MessagePort", | ||
| "fetch", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URL", | ||
| "URLSearchParams", | ||
| "FormData" | ||
| ] | ||
| }); | ||
| return { async teardown(global) { | ||
| await teardownWindow(win); | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((d, k) => Object.defineProperty(global, k, d)); | ||
| } }; | ||
| } | ||
| }; | ||
| function catchWindowErrors(window) { | ||
| let userErrorListenerCount = 0; | ||
| function throwUnhandlerError(e) { | ||
| if (userErrorListenerCount === 0 && e.error != null) { | ||
| e.preventDefault(); | ||
| process.emit("uncaughtException", e.error); | ||
| } | ||
| } | ||
| const addEventListener = window.addEventListener.bind(window); | ||
| const removeEventListener = window.removeEventListener.bind(window); | ||
| window.addEventListener("error", throwUnhandlerError); | ||
| window.addEventListener = function(...args) { | ||
| if (args[0] === "error") userErrorListenerCount++; | ||
| return addEventListener.apply(this, args); | ||
| }; | ||
| window.removeEventListener = function(...args) { | ||
| if (args[0] === "error" && userErrorListenerCount) userErrorListenerCount--; | ||
| return removeEventListener.apply(this, args); | ||
| }; | ||
| return function clearErrorHandlers() { | ||
| window.removeEventListener("error", throwUnhandlerError); | ||
| }; | ||
| } | ||
| let NodeFormData_; | ||
| let NodeBlob_; | ||
| let NodeRequest_; | ||
| var jsdom = { | ||
| name: "jsdom", | ||
| viteEnvironment: "client", | ||
| async setupVM({ jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| let dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const clearWindowErrors = catchWindowErrors(dom.window); | ||
| const utils = createCompatUtils(dom.window); | ||
| // TODO: browser doesn't expose Buffer, but a lot of dependencies use it | ||
| dom.window.Buffer = Buffer; | ||
| dom.window.jsdom = dom; | ||
| dom.window.Request = createCompatRequest(utils); | ||
| dom.window.URL = createJSDOMCompatURL(utils); | ||
| for (const name of [ | ||
| "structuredClone", | ||
| "BroadcastChannel", | ||
| "MessageChannel", | ||
| "MessagePort", | ||
| "TextEncoder", | ||
| "TextDecoder" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined" && typeof dom.window[name] === "undefined") dom.window[name] = value; | ||
| } | ||
| for (const name of [ | ||
| "fetch", | ||
| "Response", | ||
| "Headers", | ||
| "AbortController", | ||
| "AbortSignal", | ||
| "URLSearchParams" | ||
| ]) { | ||
| const value = globalThis[name]; | ||
| if (typeof value !== "undefined") dom.window[name] = value; | ||
| } | ||
| return { | ||
| getVmContext() { | ||
| return dom.getInternalVMContext(); | ||
| }, | ||
| teardown() { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| dom = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global, { jsdom = {} }) { | ||
| // delay initialization because it takes ~1s | ||
| NodeFormData_ = globalThis.FormData; | ||
| NodeBlob_ = globalThis.Blob; | ||
| NodeRequest_ = globalThis.Request; | ||
| const { CookieJar, JSDOM, ResourceLoader, VirtualConsole } = await import('jsdom'); | ||
| const { html = "<!DOCTYPE html>", userAgent, url = "http://localhost:3000", contentType = "text/html", pretendToBeVisual = true, includeNodeLocations = false, runScripts = "dangerously", resources, console = false, cookieJar = false, ...restOptions } = jsdom; | ||
| let virtualConsole; | ||
| if (console && globalThis.console) { | ||
| virtualConsole = new VirtualConsole(); | ||
| // jsdom <27 | ||
| if ("sendTo" in virtualConsole) virtualConsole.sendTo(globalThis.console); | ||
| else virtualConsole.forwardTo(globalThis.console); | ||
| } | ||
| const dom = new JSDOM(html, { | ||
| pretendToBeVisual, | ||
| resources: resources ?? (userAgent ? new ResourceLoader({ userAgent }) : void 0), | ||
| runScripts, | ||
| url, | ||
| virtualConsole, | ||
| cookieJar: cookieJar ? new CookieJar() : void 0, | ||
| includeNodeLocations, | ||
| contentType, | ||
| userAgent, | ||
| ...restOptions | ||
| }); | ||
| const clearAddEventListenerPatch = patchAddEventListener(dom.window); | ||
| const { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }); | ||
| const clearWindowErrors = catchWindowErrors(global); | ||
| const utils = createCompatUtils(dom.window); | ||
| global.jsdom = dom; | ||
| global.Request = createCompatRequest(utils); | ||
| global.URL = createJSDOMCompatURL(utils); | ||
| return { teardown(global) { | ||
| clearAddEventListenerPatch(); | ||
| clearWindowErrors(); | ||
| dom.window.close(); | ||
| delete global.jsdom; | ||
| keys.forEach((key) => delete global[key]); | ||
| originals.forEach((d, k) => Object.defineProperty(global, k, d)); | ||
| } }; | ||
| } | ||
| }; | ||
| function createCompatRequest(utils) { | ||
| class Request extends NodeRequest_ { | ||
| constructor(...args) { | ||
| const [input, init] = args; | ||
| if (init?.body != null) { | ||
| const compatInit = { ...init }; | ||
| if (init.body instanceof utils.window.Blob) compatInit.body = utils.makeCompatBlob(init.body); | ||
| if (init.body instanceof utils.window.FormData) compatInit.body = utils.makeCompatFormData(init.body); | ||
| super(input, compatInit); | ||
| } else super(...args); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof NodeRequest_; | ||
| } | ||
| } | ||
| return Request; | ||
| } | ||
| function createJSDOMCompatURL(utils) { | ||
| class URL extends URL$1 { | ||
| static createObjectURL(blob) { | ||
| if (blob instanceof utils.window.Blob) { | ||
| const compatBlob = utils.makeCompatBlob(blob); | ||
| return URL$1.createObjectURL(compatBlob); | ||
| } | ||
| return URL$1.createObjectURL(blob); | ||
| } | ||
| static [Symbol.hasInstance](instance) { | ||
| return instance instanceof URL$1; | ||
| } | ||
| } | ||
| return URL; | ||
| } | ||
| function createCompatUtils(window) { | ||
| // this returns a hidden Symbol(impl) | ||
| // this is cursed, and jsdom should just implement fetch API itself | ||
| const implSymbol = Object.getOwnPropertySymbols(Object.getOwnPropertyDescriptors(new window.Blob()))[0]; | ||
| const utils = { | ||
| window, | ||
| makeCompatFormData(formData) { | ||
| const nodeFormData = new NodeFormData_(); | ||
| formData.forEach((value, key) => { | ||
| if (value instanceof window.Blob) nodeFormData.append(key, utils.makeCompatBlob(value)); | ||
| else nodeFormData.append(key, value); | ||
| }); | ||
| return nodeFormData; | ||
| }, | ||
| makeCompatBlob(blob) { | ||
| const buffer = blob[implSymbol]._buffer; | ||
| return new NodeBlob_([buffer], { type: blob.type }); | ||
| } | ||
| }; | ||
| return utils; | ||
| } | ||
| function patchAddEventListener(window) { | ||
| const abortControllers = /* @__PURE__ */ new WeakMap(); | ||
| const JSDOMAbortSignal = window.AbortSignal; | ||
| const JSDOMAbortController = window.AbortController; | ||
| const originalAddEventListener = window.EventTarget.prototype.addEventListener; | ||
| function getJsdomAbortController(signal) { | ||
| if (!abortControllers.has(signal)) { | ||
| const jsdomAbortController = new JSDOMAbortController(); | ||
| signal.addEventListener("abort", () => { | ||
| jsdomAbortController.abort(signal.reason); | ||
| }); | ||
| abortControllers.set(signal, jsdomAbortController); | ||
| } | ||
| return abortControllers.get(signal); | ||
| } | ||
| window.EventTarget.prototype.addEventListener = function addEventListener(type, callback, options) { | ||
| if (typeof options === "object" && options?.signal != null) { | ||
| const { signal, ...otherOptions } = options; | ||
| // - this happens because AbortSignal is provided by Node.js, | ||
| // but jsdom APIs require jsdom's AbortSignal, while Node APIs | ||
| // (like fetch and Request) require a Node.js AbortSignal | ||
| // - disable narrow typing with "as any" because we need it later | ||
| if (!(signal instanceof JSDOMAbortSignal)) { | ||
| const jsdomCompatOptions = Object.create(null); | ||
| Object.assign(jsdomCompatOptions, otherOptions); | ||
| jsdomCompatOptions.signal = getJsdomAbortController(signal).signal; | ||
| return originalAddEventListener.call(this, type, callback, jsdomCompatOptions); | ||
| } | ||
| } | ||
| return originalAddEventListener.call(this, type, callback, options); | ||
| }; | ||
| return () => { | ||
| window.EventTarget.prototype.addEventListener = originalAddEventListener; | ||
| }; | ||
| } | ||
| // some globals we do not want, either because deprecated or we set it ourselves | ||
| const denyList = new Set([ | ||
| "GLOBAL", | ||
| "root", | ||
| "global", | ||
| "Buffer", | ||
| "ArrayBuffer", | ||
| "Uint8Array" | ||
| ]); | ||
| const nodeGlobals = /* @__PURE__ */ new Map(); | ||
| function populateNodeGlobals() { | ||
| if (nodeGlobals.size !== 0) return; | ||
| const names = Object.getOwnPropertyNames(globalThis); | ||
| const length = names.length; | ||
| for (let i = 0; i < length; i++) { | ||
| const globalName = names[i]; | ||
| if (!denyList.has(globalName)) { | ||
| const descriptor = Object.getOwnPropertyDescriptor(globalThis, globalName); | ||
| if (!descriptor) throw new Error(`No property descriptor for ${globalName}, this is a bug in Vitest.`); | ||
| nodeGlobals.set(globalName, descriptor); | ||
| } | ||
| } | ||
| } | ||
| var node = { | ||
| name: "node", | ||
| viteEnvironment: "ssr", | ||
| async setupVM() { | ||
| populateNodeGlobals(); | ||
| const vm = await import('node:vm'); | ||
| let context = vm.createContext(); | ||
| let global = vm.runInContext("this", context); | ||
| const contextGlobals = new Set(Object.getOwnPropertyNames(global)); | ||
| for (const [nodeGlobalsKey, descriptor] of nodeGlobals) if (!contextGlobals.has(nodeGlobalsKey)) if (descriptor.configurable) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| get() { | ||
| // @ts-expect-error: no index signature | ||
| const val = globalThis[nodeGlobalsKey]; | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: descriptor.writable === true || nodeGlobalsKey === "performance" | ||
| }); | ||
| return val; | ||
| }, | ||
| set(val) { | ||
| // override lazy getter | ||
| Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: true, | ||
| enumerable: descriptor.enumerable, | ||
| value: val, | ||
| writable: true | ||
| }); | ||
| } | ||
| }); | ||
| else if ("value" in descriptor) Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| value: descriptor.value, | ||
| writable: descriptor.writable | ||
| }); | ||
| else Object.defineProperty(global, nodeGlobalsKey, { | ||
| configurable: false, | ||
| enumerable: descriptor.enumerable, | ||
| get: descriptor.get, | ||
| set: descriptor.set | ||
| }); | ||
| global.global = global; | ||
| global.Buffer = Buffer; | ||
| global.ArrayBuffer = ArrayBuffer; | ||
| // TextEncoder (global or via 'util') references a Uint8Array constructor | ||
| // different than the global one used by users in tests. This makes sure the | ||
| // same constructor is referenced by both. | ||
| global.Uint8Array = Uint8Array; | ||
| return { | ||
| getVmContext() { | ||
| return context; | ||
| }, | ||
| teardown() { | ||
| context = void 0; | ||
| global = void 0; | ||
| } | ||
| }; | ||
| }, | ||
| async setup(global) { | ||
| global.console.Console = Console; | ||
| return { teardown(global) { | ||
| delete global.console.Console; | ||
| } }; | ||
| } | ||
| }; | ||
| const environments = { | ||
| node, | ||
| jsdom, | ||
| "happy-dom": happy, | ||
| "edge-runtime": edge | ||
| }; | ||
| export { BareModuleMocker as B, VITEST_VM_CONTEXT_SYMBOL as V, VitestModuleRunner as a, VitestTransport as b, createNodeImportMeta as c, environments as e, normalizeModuleId as n, populateGlobal as p, startVitestModuleRunner as s }; |
| import { i as init } from './init.DTAQFCjl.js'; | ||
| if (!process.send) throw new Error("Expected worker to be run in node:child_process"); | ||
| // Store globals in case tests overwrite them | ||
| const processExit = process.exit.bind(process); | ||
| const processSend = process.send.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const processRemoveAllListeners = process.removeAllListeners.bind(process); | ||
| // Work-around for nodejs/node#55094 | ||
| if (process.execArgv.some((execArg) => execArg.startsWith("--prof") || execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir"))) processOn("SIGTERM", () => processExit()); | ||
| processOn("error", onError); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (v) => processSend(v), | ||
| on: (cb) => processOn("message", cb), | ||
| off: (cb) => processOff("message", cb), | ||
| teardown: () => { | ||
| processRemoveAllListeners("message"); | ||
| processOff("error", onError); | ||
| }, | ||
| runTests: (state, traces) => executeTests("run", state, traces), | ||
| collectTests: (state, traces) => executeTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| async function executeTests(method, state, traces) { | ||
| try { | ||
| await runTests(method, state, traces); | ||
| } finally { | ||
| process.exit = processExit; | ||
| } | ||
| } | ||
| } | ||
| // Prevent leaving worker in loops where it tries to send message to closed main | ||
| // thread, errors, and tries to send the error. | ||
| function onError(error) { | ||
| if (error?.code === "ERR_IPC_CHANNEL_CLOSED" || error?.code === "EPIPE") processExit(1); | ||
| } | ||
| export { workerInit as w }; |
| import { isMainThread, parentPort } from 'node:worker_threads'; | ||
| import { i as init } from './init.DTAQFCjl.js'; | ||
| if (isMainThread || !parentPort) throw new Error("Expected worker to be run in node:worker_threads"); | ||
| function workerInit(options) { | ||
| const { runTests } = options; | ||
| init({ | ||
| post: (response) => parentPort.postMessage(response), | ||
| on: (callback) => parentPort.on("message", callback), | ||
| off: (callback) => parentPort.off("message", callback), | ||
| teardown: () => parentPort.removeAllListeners("message"), | ||
| runTests: async (state, traces) => runTests("run", state, traces), | ||
| collectTests: async (state, traces) => runTests("collect", state, traces), | ||
| setup: options.setup | ||
| }); | ||
| } | ||
| export { workerInit as w }; |
| import { readFileSync } from 'node:fs'; | ||
| import { isBuiltin } from 'node:module'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import { resolve } from 'pathe'; | ||
| import { ModuleRunner, EvaluatedModules } from 'vite/module-runner'; | ||
| import { e as environments, b as VitestTransport } from './index.DNRmy2jU.js'; | ||
| import { serializeValue } from '@vitest/utils/serialize'; | ||
| import { serializeError } from '@vitest/utils/error'; | ||
| import { disableDefaultColors } from 'tinyrainbow'; | ||
| import { Traces } from '../traces.js'; | ||
| import { o as onCancel, V as VitestEvaluatedModules, a as rpcDone, c as createRuntimeRpc } from './rpc.DZEh5xnQ.js'; | ||
| import { createStackString, parseStacktrace } from '@vitest/utils/source-map'; | ||
| import { s as setupInspect } from './inspector.CvyFGlXm.js'; | ||
| import { E as EnvironmentTeardownError } from './utils.DYj33du9.js'; | ||
| function isBuiltinEnvironment(env) { | ||
| return env in environments; | ||
| } | ||
| const isWindows = process.platform === "win32"; | ||
| const _loaders = /* @__PURE__ */ new Map(); | ||
| function createEnvironmentLoader(root, rpc) { | ||
| const cachedLoader = _loaders.get(root); | ||
| if (!cachedLoader || cachedLoader.isClosed()) { | ||
| _loaders.delete(root); | ||
| const moduleRunner = new ModuleRunner({ | ||
| hmr: false, | ||
| sourcemapInterceptor: "prepareStackTrace", | ||
| transport: new VitestTransport({ | ||
| async fetchModule(id, importer, options) { | ||
| const result = await rpc.fetch(id, importer, "__vitest__", options); | ||
| if ("cached" in result) return { | ||
| code: readFileSync(result.tmp, "utf-8"), | ||
| ...result | ||
| }; | ||
| if (isWindows && "externalize" in result) | ||
| // TODO: vitest returns paths for external modules, but Vite returns file:// | ||
| // https://github.com/vitejs/vite/pull/20449 | ||
| result.externalize = isBuiltin(id) || /^(?:node:|data:|http:|https:|file:)/.test(id) ? result.externalize : pathToFileURL(result.externalize).toString(); | ||
| return result; | ||
| }, | ||
| async resolveId(id, importer) { | ||
| return rpc.resolve(id, importer, "__vitest__"); | ||
| } | ||
| }, new EvaluatedModules(), /* @__PURE__ */ new WeakMap()) | ||
| }); | ||
| _loaders.set(root, moduleRunner); | ||
| } | ||
| return _loaders.get(root); | ||
| } | ||
| async function loadNativeEnvironment(name, root, traces) { | ||
| const packageId = name[0] === "." || name[0] === "/" ? pathToFileURL(resolve(root, name)).toString() : import.meta.resolve(`vitest-environment-${name}`, pathToFileURL(root).toString()); | ||
| return resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => import(packageId))); | ||
| } | ||
| function resolveEnvironmentFromModule(name, packageId, pkg) { | ||
| if (!pkg || !pkg.default || typeof pkg.default !== "object") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "setup" or/and "setupVM" method.`); | ||
| const environment = pkg.default; | ||
| if (environment.transformMode != null && environment.transformMode !== "web" && environment.transformMode !== "ssr") throw new TypeError(`Environment "${name}" is not a valid environment. Path "${packageId}" should export default object with a "transformMode" method equal to "ssr" or "web", received "${environment.transformMode}".`); | ||
| if (environment.transformMode) { | ||
| console.warn(`The Vitest environment ${environment.name} defines the "transformMode". This options was deprecated in Vitest 4 and will be removed in the next major version. Please, use "viteEnvironment" instead.`); | ||
| // keep for backwards compat | ||
| environment.viteEnvironment ??= environment.transformMode === "ssr" ? "ssr" : "client"; | ||
| } | ||
| return environment; | ||
| } | ||
| async function loadEnvironment(name, root, rpc, traces, viteModuleRunner) { | ||
| if (isBuiltinEnvironment(name)) return { environment: environments[name] }; | ||
| if (!viteModuleRunner) return { environment: await loadNativeEnvironment(name, root, traces) }; | ||
| const loader = createEnvironmentLoader(root, rpc); | ||
| const packageId = name[0] === "." || name[0] === "/" ? resolve(root, name) : (await traces.$("vitest.runtime.environment.resolve", () => rpc.resolve(`vitest-environment-${name}`, void 0, "__vitest__")))?.id ?? resolve(root, name); | ||
| return { | ||
| environment: resolveEnvironmentFromModule(name, packageId, await traces.$("vitest.runtime.environment.import", () => loader.import(packageId))), | ||
| loader | ||
| }; | ||
| } | ||
| const cleanupListeners = /* @__PURE__ */ new Set(); | ||
| const moduleRunnerListeners = /* @__PURE__ */ new Set(); | ||
| function onCleanup(cb) { | ||
| cleanupListeners.add(cb); | ||
| } | ||
| async function cleanup() { | ||
| await Promise.all(Array.from(cleanupListeners, (l) => l())); | ||
| } | ||
| function onModuleRunner(cb) { | ||
| moduleRunnerListeners.add(cb); | ||
| } | ||
| function emitModuleRunner(moduleRunner) { | ||
| moduleRunnerListeners.forEach((l) => l(moduleRunner)); | ||
| } | ||
| // Store globals in case tests overwrite them | ||
| const processListeners = process.listeners.bind(process); | ||
| const processOn = process.on.bind(process); | ||
| const processOff = process.off.bind(process); | ||
| const dispose = []; | ||
| function listenForErrors(state) { | ||
| dispose.forEach((fn) => fn()); | ||
| dispose.length = 0; | ||
| function catchError(err, type, event) { | ||
| const worker = state(); | ||
| // if there is another listener, assume that it's handled by user code | ||
| // one is Vitest's own listener | ||
| if (processListeners(event).length > 1) return; | ||
| const error = serializeValue(err); | ||
| if (typeof error === "object" && error != null) { | ||
| error.VITEST_TEST_NAME = worker.current?.type === "test" ? worker.current.name : void 0; | ||
| if (worker.filepath) error.VITEST_TEST_PATH = worker.filepath; | ||
| } | ||
| state().rpc.onUnhandledError(error, type); | ||
| } | ||
| const uncaughtException = (e) => catchError(e, "Uncaught Exception", "uncaughtException"); | ||
| const unhandledRejection = (e) => catchError(e, "Unhandled Rejection", "unhandledRejection"); | ||
| processOn("uncaughtException", uncaughtException); | ||
| processOn("unhandledRejection", unhandledRejection); | ||
| dispose.push(() => { | ||
| processOff("uncaughtException", uncaughtException); | ||
| processOff("unhandledRejection", unhandledRejection); | ||
| }); | ||
| } | ||
| class GetterTracker { | ||
| static EXPORTS_MAX_INVOCATIONS = 1e6; | ||
| invocations = /* @__PURE__ */ new Map(); | ||
| excessiveInvocations = /* @__PURE__ */ new Map(); | ||
| createTracker(moduleId, defineExport) { | ||
| return (name, getter) => { | ||
| const key = `${moduleId}:${name}`; | ||
| defineExport(name, () => { | ||
| const count = (this.invocations.get(key) || 0) + 1; | ||
| this.invocations.set(key, count); | ||
| if (count > GetterTracker.EXPORTS_MAX_INVOCATIONS && !this.excessiveInvocations.has(key)) this.excessiveInvocations.set(key, { | ||
| moduleId, | ||
| exportName: name | ||
| }); | ||
| return getter(); | ||
| }); | ||
| }; | ||
| } | ||
| resetInvocations() { | ||
| this.invocations.clear(); | ||
| this.excessiveInvocations.clear(); | ||
| } | ||
| getExcessiveInvocations() { | ||
| return [...this.excessiveInvocations.values()]; | ||
| } | ||
| } | ||
| const resolvingModules = /* @__PURE__ */ new Set(); | ||
| async function execute(method, ctx, worker, traces) { | ||
| const prepareStart = performance.now(); | ||
| const cleanups = [setupInspect(ctx)]; | ||
| // RPC is used to communicate between worker (be it a thread worker or child process or a custom implementation) and the main thread | ||
| const rpc = ctx.rpc; | ||
| try { | ||
| // do not close the RPC channel so that we can get the error messages sent to the main thread | ||
| cleanups.push(async () => { | ||
| await Promise.all(rpc.$rejectPendingCalls(({ method, reject }) => { | ||
| reject(new EnvironmentTeardownError(`[vitest-worker]: Closing rpc while "${method}" was pending`)); | ||
| })); | ||
| }); | ||
| const state = { | ||
| ctx, | ||
| evaluatedModules: new VitestEvaluatedModules(), | ||
| resolvingModules, | ||
| moduleExecutionInfo: /* @__PURE__ */ new Map(), | ||
| config: ctx.config, | ||
| environment: null, | ||
| durations: { | ||
| environment: 0, | ||
| prepare: prepareStart | ||
| }, | ||
| rpc, | ||
| onCancel, | ||
| onCleanup: onCleanup, | ||
| providedContext: ctx.providedContext, | ||
| onFilterStackTrace(stack) { | ||
| return createStackString(parseStacktrace(stack)); | ||
| }, | ||
| metaEnv: createImportMetaEnvProxy(), | ||
| getterTracker: ctx.config.benchmark.enabled && !ctx.config.benchmark.suppressExportGetterWarnings ? new GetterTracker() : void 0 | ||
| }; | ||
| const methodName = method === "collect" ? "collectTests" : "runTests"; | ||
| if (!worker[methodName] || typeof worker[methodName] !== "function") throw new TypeError(`Test worker should expose "runTests" method. Received "${typeof worker.runTests}".`); | ||
| await worker[methodName](state, traces); | ||
| } finally { | ||
| await rpcDone().catch(() => {}); | ||
| await Promise.all(cleanups.map((fn) => fn())).catch(() => {}); | ||
| } | ||
| } | ||
| function run(ctx, worker, traces) { | ||
| return execute("run", ctx, worker, traces); | ||
| } | ||
| function collect(ctx, worker, traces) { | ||
| return execute("collect", ctx, worker, traces); | ||
| } | ||
| async function teardown() { | ||
| await cleanup(); | ||
| } | ||
| const env = process.env; | ||
| function createImportMetaEnvProxy() { | ||
| // packages/vitest/src/node/plugins/index.ts:146 | ||
| const booleanKeys = [ | ||
| "DEV", | ||
| "PROD", | ||
| "SSR" | ||
| ]; | ||
| return new Proxy(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; | ||
| } | ||
| }); | ||
| } | ||
| const __vitest_worker_response__ = true; | ||
| const memoryUsage = process.memoryUsage.bind(process); | ||
| let reportMemory = false; | ||
| let traces; | ||
| /** @experimental */ | ||
| function init(worker) { | ||
| worker.on(onMessage); | ||
| if (worker.onModuleRunner) onModuleRunner(worker.onModuleRunner); | ||
| let runPromise; | ||
| let isRunning = false; | ||
| let workerTeardown; | ||
| let setupContext; | ||
| let poolId; | ||
| function send(response) { | ||
| worker.post(worker.serialize ? worker.serialize(response) : response); | ||
| } | ||
| async function onMessage(rawMessage) { | ||
| const message = worker.deserialize ? worker.deserialize(rawMessage) : rawMessage; | ||
| if (message?.__vitest_worker_request__ !== true) return; | ||
| switch (message.type) { | ||
| case "start": { | ||
| process.env.VITEST_POOL_ID = String(message.poolId); | ||
| process.env.VITEST_WORKER_ID = String(message.workerId); | ||
| reportMemory = message.options.reportMemory; | ||
| poolId = message.poolId; | ||
| if (message.context.config.disableColors) disableDefaultColors(); | ||
| traces ??= await new Traces({ | ||
| enabled: message.traces.enabled, | ||
| sdkPath: message.traces.sdkPath | ||
| }).waitInit(); | ||
| const { environment, config, pool } = message.context; | ||
| const context = traces.getContextFromCarrier(message.traces.otelCarrier); | ||
| // record telemetry as part of "start" | ||
| traces.recordInitSpan(context); | ||
| try { | ||
| setupContext = { | ||
| environment, | ||
| config, | ||
| pool, | ||
| rpc: createRuntimeRpc(worker), | ||
| projectName: config.name || "", | ||
| traces | ||
| }; | ||
| workerTeardown = await traces.$("vitest.runtime.setup", { context }, () => worker.setup?.(setupContext)); | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "started", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error) | ||
| }); | ||
| } | ||
| break; | ||
| } | ||
| case "run": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.run", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => run({ | ||
| ...setupContext, | ||
| ...message.context, | ||
| concurrencyId: poolId | ||
| }, worker, traces).catch((error) => serializeError(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "collect": | ||
| // Prevent concurrent execution if worker is already running | ||
| if (isRunning) { | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(/* @__PURE__ */ new Error("[vitest-worker]: Worker is already running tests")) | ||
| }); | ||
| return; | ||
| } | ||
| try { | ||
| process.env.VITEST_WORKER_ID = String(message.context.workerId); | ||
| } catch (error) { | ||
| return send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: serializeError(error), | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } | ||
| isRunning = true; | ||
| try { | ||
| const tracesContext = traces.getContextFromCarrier(message.otelCarrier); | ||
| runPromise = traces.$("vitest.runtime.collect", { | ||
| context: tracesContext, | ||
| attributes: { | ||
| "vitest.worker.specifications": traces.isEnabled() ? getFilesWithLocations(message.context.files) : [], | ||
| "vitest.worker.id": message.context.workerId | ||
| } | ||
| }, () => collect({ | ||
| ...setupContext, | ||
| ...message.context, | ||
| concurrencyId: poolId | ||
| }, worker, traces).catch((error) => serializeError(error))); | ||
| send({ | ||
| type: "testfileFinished", | ||
| __vitest_worker_response__, | ||
| error: await runPromise, | ||
| usedMemory: reportMemory ? memoryUsage().heapUsed : void 0 | ||
| }); | ||
| } finally { | ||
| runPromise = void 0; | ||
| isRunning = false; | ||
| } | ||
| break; | ||
| case "stop": | ||
| await runPromise; | ||
| try { | ||
| const context = traces.getContextFromCarrier(message.otelCarrier); | ||
| const error = await traces.$("vitest.runtime.teardown", { context }, async () => { | ||
| const error = await teardown().catch((error) => serializeError(error)); | ||
| await workerTeardown?.(); | ||
| return error; | ||
| }); | ||
| await traces.finish(); | ||
| send({ | ||
| type: "stopped", | ||
| error, | ||
| __vitest_worker_response__ | ||
| }); | ||
| } catch (error) { | ||
| send({ | ||
| type: "stopped", | ||
| error: serializeError(error), | ||
| __vitest_worker_response__ | ||
| }); | ||
| } | ||
| worker.teardown?.(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| function getFilesWithLocations(files) { | ||
| return files.flatMap((file) => { | ||
| if (!file.testLocations) return file.filepath; | ||
| return file.testLocations.map((location) => { | ||
| return `${file}:${location}`; | ||
| }); | ||
| }); | ||
| } | ||
| export { listenForErrors as a, emitModuleRunner as e, init as i, loadEnvironment as l }; |
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| import { MessageChannel } from 'node:worker_threads'; | ||
| import { initSyntaxLexers, hoistMocks } from '@vitest/mocker/transforms'; | ||
| import { cleanUrl } from '@vitest/utils/helpers'; | ||
| import { p as parse } from './acorn.B2iPLyUM.js'; | ||
| import MagicString from 'magic-string'; | ||
| import { resolve } from 'pathe'; | ||
| import c from 'tinyrainbow'; | ||
| import { distDir } from '../path.js'; | ||
| import { t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import 'node:path'; | ||
| const NOW_LENGTH = Date.now().toString().length; | ||
| const REGEXP_VITEST = new RegExp(`%3Fvitest=\\d{${NOW_LENGTH}}`); | ||
| const REGEXP_MOCK_ACTUAL = /\?mock=actual/; | ||
| async function setupNodeLoaderHooks(worker) { | ||
| if (module$1.setSourceMapsSupport) module$1.setSourceMapsSupport(true); | ||
| else if (process.setSourceMapsEnabled) process.setSourceMapsEnabled(true); | ||
| if (worker.config.experimental.nodeLoader !== false) await initSyntaxLexers(); | ||
| if (typeof module$1.registerHooks === "function") module$1.registerHooks({ | ||
| resolve(specifier, context, nextResolve) { | ||
| if (specifier.includes("mock=actual")) { | ||
| // url is already resolved by `importActual` | ||
| const moduleId = specifier.replace(REGEXP_MOCK_ACTUAL, ""); | ||
| const builtin = isBuiltin(moduleId); | ||
| return { | ||
| url: builtin ? toBuiltin(moduleId) : moduleId, | ||
| format: builtin ? "builtin" : void 0, | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| const isVitest = specifier.includes("%3Fvitest="); | ||
| const result = nextResolve(isVitest ? specifier.replace(REGEXP_VITEST, "") : specifier, context); | ||
| // avoid tracking /node_modules/ module graph for performance reasons | ||
| if (context.parentURL && result.url && !result.url.includes("/node_modules/")) worker.rpc.ensureModuleGraphEntry(result.url, context.parentURL).catch(() => { | ||
| // ignore errors | ||
| }); | ||
| // this is require for in-source tests to be invalidated if | ||
| // one of the files already imported it in --maxWorkers=1 --no-isolate | ||
| if (isVitest) result.url = `${result.url}?vitest=${Date.now()}`; | ||
| if (worker.config.experimental.nodeLoader === false || !context.parentURL || result.url.includes(distDir) || context.parentURL?.toString().includes(distDir)) return result; | ||
| const mockedResult = getNativeMocker()?.resolveMockedModule(result.url, context.parentURL); | ||
| if (mockedResult != null) return mockedResult; | ||
| return result; | ||
| }, | ||
| load: worker.config.experimental.nodeLoader === false ? void 0 : createLoadHook() | ||
| }); | ||
| else if (module$1.register) { | ||
| if (worker.config.experimental.nodeLoader !== false) console.warn(`${c.bgYellow(" WARNING ")} "module.registerHooks" is not supported in Node.js ${process.version}. This means that some features like module mocking or in-source testing are not supported. Upgrade your Node.js version to at least 22.15 or disable "experimental.nodeLoader" flag manually.\n`); | ||
| const { port1, port2 } = new MessageChannel(); | ||
| port1.unref(); | ||
| port2.unref(); | ||
| port1.on("message", (data) => { | ||
| if (!data || typeof data !== "object") return; | ||
| switch (data.event) { | ||
| case "register-module-graph-entry": { | ||
| const { url, parentURL } = data; | ||
| worker.rpc.ensureModuleGraphEntry(url, parentURL); | ||
| return; | ||
| } | ||
| default: console.error("Unknown message event:", data.event); | ||
| } | ||
| }); | ||
| /** Registers {@link file://./../nodejsWorkerLoader.ts} */ | ||
| module$1.register("#nodejs-worker-loader", { | ||
| parentURL: import.meta.url, | ||
| data: { port: port2 }, | ||
| transferList: [port2] | ||
| }); | ||
| } else if (!process.versions.deno && !process.versions.bun) console.warn("\"module.registerHooks\" and \"module.register\" are not supported. Some Vitest features may not work. Please, use Node.js 18.19.0 or higher."); | ||
| } | ||
| function replaceInSourceMarker(url, source, ms) { | ||
| const re = /import\.meta\.vitest/g; | ||
| let match; | ||
| let overridden = false; | ||
| // eslint-disable-next-line no-cond-assign | ||
| while (match = re.exec(source)) { | ||
| const { index, "0": code } = match; | ||
| overridden = true; | ||
| // should it support process.vitest for CJS modules? | ||
| ms().overwrite(index, index + code.length, "IMPORT_META_TEST()"); | ||
| } | ||
| if (overridden) { | ||
| const filename = resolve(fileURLToPath(url)); | ||
| // appending instead of prepending because functions are hoisted and we don't change the offset | ||
| ms().append(`;\nfunction IMPORT_META_TEST() { return typeof __vitest_worker__ !== 'undefined' && __vitest_worker__.filepath === "${filename.replace(/"/g, "\\\"")}" ? __vitest_index__ : undefined; }`); | ||
| } | ||
| } | ||
| const ignoreFormats = new Set([ | ||
| "addon", | ||
| "builtin", | ||
| "wasm" | ||
| ]); | ||
| function createLoadHook(_worker) { | ||
| return (url, context, nextLoad) => { | ||
| const result = url.includes("mock=") && isBuiltin(cleanUrl(url)) ? { format: "commonjs" } : nextLoad(url, context); | ||
| if (result.format && ignoreFormats.has(result.format) || url.includes(distDir)) return result; | ||
| const mocker = getNativeMocker(); | ||
| mocker?.checkCircularManualMock(url); | ||
| if (url.includes("mock=automock") || url.includes("mock=autospy")) { | ||
| const automockedResult = mocker?.loadAutomock(url, result); | ||
| if (automockedResult != null) return automockedResult; | ||
| return result; | ||
| } | ||
| if (url.includes("mock=manual")) { | ||
| const mockedResult = mocker?.loadManualMock(url, result); | ||
| if (mockedResult != null) return mockedResult; | ||
| return result; | ||
| } | ||
| // ignore non-vitest modules for performance reasons, | ||
| // vi.hoisted and vi.mock won't work outside of test files or setup files | ||
| if (!result.source || !url.includes("vitest=")) return result; | ||
| const filename = url.startsWith("file://") ? fileURLToPath(url) : url; | ||
| const source = result.source.toString(); | ||
| const transformedCode = result.format?.includes("typescript") ? module$1.stripTypeScriptTypes(source) : source; | ||
| let _ms; | ||
| const ms = () => _ms || (_ms = new MagicString(source)); | ||
| if (source.includes("import.meta.vitest")) replaceInSourceMarker(url, source, ms); | ||
| hoistMocks(transformedCode, filename, (code) => parse(code, { | ||
| ecmaVersion: "latest", | ||
| sourceType: result.format === "module" || result.format === "module-typescript" || result.format === "typescript" ? "module" : "script" | ||
| }), { | ||
| magicString: ms, | ||
| globalThisAccessor: "\"__vitest_mocker__\"" | ||
| }); | ||
| let code; | ||
| if (_ms) code = `${_ms.toString()}\n//# sourceMappingURL=${genSourceMapUrl(_ms.generateMap({ | ||
| hires: "boundary", | ||
| source: filename | ||
| }))}`; | ||
| else code = source; | ||
| return { | ||
| format: result.format, | ||
| shortCircuit: true, | ||
| source: code | ||
| }; | ||
| }; | ||
| } | ||
| function genSourceMapUrl(map) { | ||
| if (typeof map !== "string") map = JSON.stringify(map); | ||
| return `data:application/json;base64,${Buffer.from(map).toString("base64")}`; | ||
| } | ||
| function getNativeMocker() { | ||
| return typeof __vitest_mocker__ !== "undefined" ? __vitest_mocker__ : void 0; | ||
| } | ||
| export { setupNodeLoaderHooks }; |
| import module$1, { isBuiltin } from 'node:module'; | ||
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import { automockModule, createManualModuleSource, collectModuleExports } from '@vitest/mocker/transforms'; | ||
| import { cleanUrl, createDefer } from '@vitest/utils/helpers'; | ||
| import { p as parse } from './acorn.B2iPLyUM.js'; | ||
| import { isAbsolute } from 'pathe'; | ||
| import { t as toBuiltin } from './modules.BJuCwlRJ.js'; | ||
| import { B as BareModuleMocker, n as normalizeModuleId } from './index.DNRmy2jU.js'; | ||
| import 'node:fs'; | ||
| import './utils.DYj33du9.js'; | ||
| import '../path.js'; | ||
| import 'node:path'; | ||
| import '../module-evaluator.js'; | ||
| import 'node:vm'; | ||
| import 'vite/module-runner'; | ||
| import '../traces.js'; | ||
| import '@vitest/mocker'; | ||
| import '@vitest/mocker/redirect'; | ||
| import 'node:console'; | ||
| class NativeModuleMocker extends BareModuleMocker { | ||
| wrapDynamicImport(moduleFactory) { | ||
| if (typeof moduleFactory === "function") return new Promise((resolve, reject) => { | ||
| this.resolveMocks().finally(() => { | ||
| moduleFactory().then(resolve, reject); | ||
| }); | ||
| }); | ||
| return moduleFactory; | ||
| } | ||
| resolveMockedModule(url, parentURL) { | ||
| // don't mock modules inside of packages because there is | ||
| // a high chance that it uses `require` which is not mockable | ||
| // because we use top-level await in "manual" mocks. | ||
| // for the sake of consistency we don't support mocking anything at all | ||
| if (parentURL.includes("/node_modules/")) return; | ||
| const moduleId = normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url); | ||
| const mockedModule = this.getDependencyMock(moduleId); | ||
| if (!mockedModule) return; | ||
| if (mockedModule.type === "redirect") return { | ||
| url: pathToFileURL(mockedModule.redirect).toString(), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "automock" || mockedModule.type === "autospy") return { | ||
| url: injectQuery(url, parentURL, `mock=${mockedModule.type}`), | ||
| shortCircuit: true | ||
| }; | ||
| if (mockedModule.type === "manual") return { | ||
| url: injectQuery(url, parentURL, "mock=manual"), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| loadAutomock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| let source; | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(moduleId); | ||
| const exports$1 = Object.keys(builtinModule); | ||
| source = ` | ||
| import * as builtinModule from '${toBuiltin(moduleId)}?mock=actual' | ||
| ${exports$1.map((key, index) => { | ||
| return ` | ||
| const __${index} = builtinModule["${key}"] | ||
| export { __${index} as "${key}" } | ||
| `; | ||
| }).join("")}`; | ||
| } else source = result.source?.toString(); | ||
| if (source == null) return; | ||
| const mockType = url.includes("mock=automock") ? "automock" : "autospy"; | ||
| const transformedCode = transformCode(source, result.format || "module", moduleId); | ||
| try { | ||
| const ms = automockModule(transformedCode, mockType, (code) => parse(code, { | ||
| sourceType: "module", | ||
| ecmaVersion: "latest" | ||
| }), { id: moduleId }); | ||
| return { | ||
| format: "module", | ||
| source: `${ms.toString()}\n//# sourceMappingURL=${genSourceMapUrl(ms.generateMap({ | ||
| hires: "boundary", | ||
| source: moduleId | ||
| }))}`, | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Cannot automock '${url}' because it failed to parse.`, { cause }); | ||
| } | ||
| } | ||
| loadManualMock(url, result) { | ||
| const moduleId = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| // should not be possible | ||
| if (this.getDependencyMock(moduleId)?.type !== "manual") { | ||
| console.warn(`Vitest detected unregistered manual mock ${moduleId}. This is a bug in Vitest. Please, open a new issue with reproduction.`); | ||
| return; | ||
| } | ||
| if (isBuiltin(moduleId)) { | ||
| const builtinModule = getBuiltinModule(toBuiltin(moduleId)); | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, Object.keys(builtinModule)), | ||
| shortCircuit: true | ||
| }; | ||
| } | ||
| if (!result.source) return; | ||
| const transformedCode = transformCode(result.source.toString(), result.format || "module", moduleId); | ||
| if (transformedCode == null) return; | ||
| const format = result.format?.startsWith("module") ? "module" : "commonjs"; | ||
| try { | ||
| return { | ||
| format: "module", | ||
| source: createManualModuleSource(moduleId, collectModuleExports(moduleId, transformedCode, format)), | ||
| shortCircuit: true | ||
| }; | ||
| } catch (cause) { | ||
| throw new Error(`Failed to mock '${url}'. See the cause for more information.`, { cause }); | ||
| } | ||
| } | ||
| processedModules = /* @__PURE__ */ new Map(); | ||
| checkCircularManualMock(url) { | ||
| const id = cleanUrl(normalizeModuleId(url.startsWith("file://") ? fileURLToPath(url) : url)); | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 0) + 1); | ||
| // the module is mocked and requested a second time, let's resolve | ||
| // the factory function that will redefine the exports later | ||
| if (this.originalModulePromises.has(id)) { | ||
| const factoryPromise = this.factoryPromises.get(id); | ||
| this.originalModulePromises.get(id)?.resolve({ __factoryPromise: factoryPromise }); | ||
| } | ||
| } | ||
| originalModulePromises = /* @__PURE__ */ new Map(); | ||
| factoryPromises = /* @__PURE__ */ new Map(); | ||
| // potential performance improvement: | ||
| // store by URL, not ids, no need to call url.*to* methods and normalizeModuleId | ||
| getFactoryModule(id) { | ||
| const mock = this.getMockerRegistry().getById(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 mockResult = mock.resolve(); | ||
| if (mockResult instanceof Promise) { | ||
| // to avoid circular dependency, we resolve this function as {__factoryPromise} in `checkCircularManualMock` | ||
| // when it's requested the second time. then the exports are exposed as `undefined`, | ||
| // but later redefined when the promise is actually resolved | ||
| const promise = createDefer(); | ||
| promise.finally(() => { | ||
| this.originalModulePromises.delete(id); | ||
| }); | ||
| mockResult.then(promise.resolve, promise.reject).finally(() => { | ||
| this.factoryPromises.delete(id); | ||
| }); | ||
| this.factoryPromises.set(id, mockResult); | ||
| this.originalModulePromises.set(id, promise); | ||
| // Node.js on windows processes all the files first, and then runs them | ||
| // unlike Node.js logic on Mac and Unix where it also runs the code while evaluating | ||
| // So on Linux/Mac this `if` won't be hit because `checkCircularManualMock` will resolve it | ||
| // And on Windows, the `checkCircularManualMock` will never have `originalModulePromises` | ||
| // because `getFactoryModule` is not called until the evaluation phase | ||
| // But if we track how many times the module was transformed, | ||
| // we can deduce when to return `__factoryPromise` to support circular modules | ||
| if ((this.processedModules.get(id) ?? 0) > 1) { | ||
| this.processedModules.set(id, (this.processedModules.get(id) ?? 1) - 1); | ||
| promise.resolve({ __factoryPromise: mockResult }); | ||
| } | ||
| return promise; | ||
| } | ||
| return mockResult; | ||
| } | ||
| importActual(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "actual"); | ||
| return import(url.toString()); | ||
| } | ||
| importMock(rawId, importer) { | ||
| const resolvedId = import.meta.resolve(rawId, pathToFileURL(importer).toString()); | ||
| // file is already mocked | ||
| if (resolvedId.includes("mock=")) return import(resolvedId); | ||
| const filename = fileURLToPath(resolvedId); | ||
| const external = !isAbsolute(filename) || this.isModuleDirectory(resolvedId) ? normalizeModuleId(rawId) : null; | ||
| // file is not mocked, automock or redirect it | ||
| const redirect = this.findMockRedirect(filename, external); | ||
| if (redirect) return import(pathToFileURL(redirect).toString()); | ||
| const url = new URL(resolvedId); | ||
| url.searchParams.set("mock", "automock"); | ||
| return import(url.toString()); | ||
| } | ||
| } | ||
| const replacePercentageRE = /%/g; | ||
| function injectQuery(url, importer, queryToInject) { | ||
| const { search, hash } = new URL(url.replace(replacePercentageRE, "%25"), importer); | ||
| return `${cleanUrl(url)}?${queryToInject}${search ? `&${search.slice(1)}` : ""}${hash ?? ""}`; | ||
| } | ||
| let __require; | ||
| function getBuiltinModule(moduleId) { | ||
| __require ??= module$1.createRequire(import.meta.url); | ||
| return __require(`${moduleId}?mock=actual`); | ||
| } | ||
| function genSourceMapUrl(map) { | ||
| if (typeof map !== "string") map = JSON.stringify(map); | ||
| return `data:application/json;base64,${Buffer.from(map).toString("base64")}`; | ||
| } | ||
| function transformCode(code, format, filename) { | ||
| if (format.includes("typescript")) { | ||
| if (!module$1.stripTypeScriptTypes) throw new Error(`Cannot parse '${filename}' because "module.stripTypeScriptTypes" is not supported. Module mocking requires Node.js 22.15 or higher. This is NOT a bug of Vitest.`); | ||
| return module$1.stripTypeScriptTypes(code); | ||
| } | ||
| return code; | ||
| } | ||
| export { NativeModuleMocker }; |
| import { pathToFileURL } from 'node:url'; | ||
| import { r as resolveModule } from './index.CesbTg1C.js'; | ||
| import { resolve } from 'pathe'; | ||
| import { ModuleRunner } from 'vite/module-runner'; | ||
| class NativeModuleRunner extends ModuleRunner { | ||
| /** | ||
| * @internal | ||
| */ | ||
| mocker; | ||
| constructor(root, mocker) { | ||
| super({ | ||
| hmr: false, | ||
| sourcemapInterceptor: false, | ||
| transport: { invoke() { | ||
| throw new Error("Unexpected `invoke`"); | ||
| } } | ||
| }); | ||
| this.root = root; | ||
| this.mocker = mocker; | ||
| if (mocker) Object.defineProperty(globalThis, "__vitest_mocker__", { | ||
| configurable: true, | ||
| writable: true, | ||
| value: mocker | ||
| }); | ||
| } | ||
| async import(moduleId) { | ||
| const path = resolveModule(moduleId, { paths: [this.root] }) ?? resolve(this.root, moduleId); | ||
| // resolveModule doesn't keep the query params, so we need to add them back | ||
| let queryParams = ""; | ||
| if (moduleId.includes("?") && !path.includes("?")) queryParams = moduleId.slice(moduleId.indexOf("?")); | ||
| return import(pathToFileURL(path + queryParams).toString()); | ||
| } | ||
| } | ||
| export { NativeModuleRunner as N }; |
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import { promises, existsSync } from 'node:fs'; | ||
| import { isAbsolute, resolve, dirname, join, basename } from 'pathe'; | ||
| class NodeSnapshotEnvironment { | ||
| constructor(options = {}) { | ||
| this.options = options; | ||
| } | ||
| getVersion() { | ||
| return "1"; | ||
| } | ||
| getHeader() { | ||
| return `// Snapshot v${this.getVersion()}`; | ||
| } | ||
| async resolveRawPath(testPath, rawPath) { | ||
| return isAbsolute(rawPath) ? rawPath : resolve(dirname(testPath), rawPath); | ||
| } | ||
| async resolvePath(filepath) { | ||
| return join(join(dirname(filepath), this.options.snapshotsDirName ?? "__snapshots__"), `${basename(filepath)}.snap`); | ||
| } | ||
| async prepareDirectory(dirPath) { | ||
| await promises.mkdir(dirPath, { recursive: true }); | ||
| } | ||
| async saveSnapshotFile(filepath, snapshot) { | ||
| await promises.mkdir(dirname(filepath), { recursive: true }); | ||
| await promises.writeFile(filepath, snapshot, "utf-8"); | ||
| } | ||
| async readSnapshotFile(filepath) { | ||
| if (!existsSync(filepath)) return null; | ||
| return promises.readFile(filepath, "utf-8"); | ||
| } | ||
| async removeSnapshotFile(filepath) { | ||
| if (existsSync(filepath)) await promises.unlink(filepath); | ||
| } | ||
| } | ||
| class VitestNodeSnapshotEnvironment extends NodeSnapshotEnvironment { | ||
| getHeader() { | ||
| return `// Vitest Snapshot v${this.getVersion()}, https://vitest.dev/guide/snapshot.html`; | ||
| } | ||
| resolvePath(filepath) { | ||
| return getWorkerState().rpc.resolveSnapshotPath(filepath); | ||
| } | ||
| } | ||
| export { VitestNodeSnapshotEnvironment }; |
Sorry, the diff of this file is too big to display
| import { plugins } from '@vitest/pretty-format'; | ||
| const serialize = (val, config, indentation, depth, refs, printer) => { | ||
| // Serialize a non-default name, even if config.printFunctionName is false. | ||
| const name = val.getMockName(); | ||
| const nameString = name === "vi.fn()" ? "" : ` ${name}`; | ||
| let callsString = ""; | ||
| if (val.mock.calls.length !== 0) { | ||
| const indentationNext = indentation + config.indent; | ||
| callsString = ` {${config.spacingOuter}${indentationNext}"calls": ${printer(val.mock.calls, config, indentationNext, depth, refs)}${config.min ? ", " : ","}${config.spacingOuter}${indentationNext}"results": ${printer(val.mock.results, config, indentationNext, depth, refs)}${config.min ? "" : ","}${config.spacingOuter}${indentation}}`; | ||
| } | ||
| return `[MockFunction${nameString}]${callsString}`; | ||
| }; | ||
| const test = (val) => val && !!val._isMockFunction; | ||
| const plugin = { | ||
| serialize, | ||
| test | ||
| }; | ||
| const { DOMCollection, DOMElement, Immutable, ReactElement, ReactTestComponent, AsymmetricMatcher } = plugins; | ||
| let PLUGINS = [ | ||
| ReactTestComponent, | ||
| ReactElement, | ||
| DOMElement, | ||
| DOMCollection, | ||
| Immutable, | ||
| AsymmetricMatcher, | ||
| plugin | ||
| ]; | ||
| function addSerializer(plugin) { | ||
| PLUGINS = [plugin].concat(PLUGINS); | ||
| } | ||
| function getSerializers() { | ||
| return PLUGINS; | ||
| } | ||
| export { addSerializer as a, getSerializers as g }; |
| import { aN as FetchCachedFileSystemResult, aO as ResolveFunctionResult, U as UserConsoleLog, aL as AsyncLeak, F as File, u as AfterSuiteRunMeta, am as TestBenchmark, a as TestArtifact, b as TaskResultPack, c as TaskEventPack, q as CancelReason, a7 as SnapshotResult, B as BaselineData } from './config.d.CKWK3nld.js'; | ||
| import { FetchFunctionOptions, FetchResult } from 'vite/module-runner'; | ||
| interface OTELCarrier { | ||
| traceparent?: string; | ||
| tracestate?: string; | ||
| } | ||
| interface TracesOptions { | ||
| enabled: boolean; | ||
| watchMode?: boolean; | ||
| sdkPath?: string; | ||
| tracerName?: string; | ||
| } | ||
| declare class Traces { | ||
| #private; | ||
| constructor(options: TracesOptions); | ||
| isEnabled(): boolean; | ||
| } | ||
| declare class GetterTracker { | ||
| static EXPORTS_MAX_INVOCATIONS: number; | ||
| private invocations; | ||
| private excessiveInvocations; | ||
| createTracker(moduleId: string, defineExport: (name: string, getter: () => unknown) => void): (name: string, getter: () => unknown) => void; | ||
| resetInvocations(): void; | ||
| getExcessiveInvocations(): GetterTrackerExport[]; | ||
| } | ||
| interface GetterTrackerExport { | ||
| moduleId: string; | ||
| exportName: string; | ||
| } | ||
| interface RuntimeRPC { | ||
| fetch: (id: string, importer: string | undefined, environment: string, options?: FetchFunctionOptions, otelCarrier?: OTELCarrier) => Promise<FetchResult | FetchCachedFileSystemResult>; | ||
| resolve: (id: string, importer: string | undefined, environment: string) => Promise<ResolveFunctionResult | null>; | ||
| transform: (id: string) => Promise<{ | ||
| code?: string; | ||
| }>; | ||
| onUserConsoleLog: (log: UserConsoleLog) => void; | ||
| onUnhandledError: (err: unknown, type: string) => void; | ||
| onAsyncLeaks: (leak: AsyncLeak[]) => void; | ||
| onQueued: (file: File) => void; | ||
| onCollected: (files: File[]) => Promise<void>; | ||
| onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void; | ||
| onTestBenchmark: (testId: string, bench: TestBenchmark) => void; | ||
| onTaskArtifactRecord: <Artifact extends TestArtifact>(testId: string, artifact: Artifact) => Promise<Artifact>; | ||
| onTaskUpdate: (pack: TaskResultPack[], events: TaskEventPack[]) => Promise<void>; | ||
| onCancel: (reason: CancelReason) => void; | ||
| getCountOfFailedTests: () => number; | ||
| snapshotSaved: (snapshot: SnapshotResult) => void; | ||
| resolveSnapshotPath: (testPath: string) => string; | ||
| readBenchmarkResult: (relativePath: string) => Promise<BaselineData | null>; | ||
| writeBenchmarkResult: (relativePath: string, data: BaselineData) => Promise<void>; | ||
| ensureModuleGraphEntry: (id: string, importer: string) => void; | ||
| } | ||
| interface RunnerRPC { | ||
| onCancel: (reason: CancelReason) => void; | ||
| } | ||
| export { GetterTracker as G, Traces as T }; | ||
| export type { OTELCarrier as O, RunnerRPC as R, RuntimeRPC as a }; |
| import { dirname, resolve } from 'pathe'; | ||
| import { EvaluatedModules } from 'vite/module-runner'; | ||
| import { getSafeTimers } from '@vitest/utils/timers'; | ||
| import { c as createBirpc } from './index.Chj8NDwU.js'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| /* Ported from https://github.com/boblauer/MockDate/blob/master/src/mockdate.ts */ | ||
| /* | ||
| The MIT License (MIT) | ||
| Copyright (c) 2014 Bob Lauer | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. | ||
| */ | ||
| const RealDate = Date; | ||
| let now = null; | ||
| class MockDate extends RealDate { | ||
| constructor(y, m, d, h, M, s, ms) { | ||
| super(); | ||
| let date; | ||
| switch (arguments.length) { | ||
| case 0: | ||
| if (now !== null) date = new RealDate(now.valueOf()); | ||
| else date = new RealDate(); | ||
| break; | ||
| case 1: | ||
| date = new RealDate(y); | ||
| break; | ||
| default: | ||
| d = typeof d === "undefined" ? 1 : d; | ||
| h = h || 0; | ||
| M = M || 0; | ||
| s = s || 0; | ||
| ms = ms || 0; | ||
| date = new RealDate(y, m, d, h, M, s, ms); | ||
| break; | ||
| } | ||
| Object.setPrototypeOf(date, MockDate.prototype); | ||
| return date; | ||
| } | ||
| } | ||
| MockDate.UTC = RealDate.UTC; | ||
| MockDate.now = function() { | ||
| return new MockDate().valueOf(); | ||
| }; | ||
| MockDate.parse = function(dateString) { | ||
| return RealDate.parse(dateString); | ||
| }; | ||
| MockDate.toString = function() { | ||
| return RealDate.toString(); | ||
| }; | ||
| function mockDate(date) { | ||
| const dateObj = new RealDate(date.valueOf()); | ||
| if (Number.isNaN(dateObj.getTime())) throw new TypeError(`mockdate: The time set is an invalid date: ${date}`); | ||
| // @ts-expect-error global | ||
| globalThis.Date = MockDate; | ||
| now = dateObj.valueOf(); | ||
| } | ||
| function resetDate() { | ||
| globalThis.Date = RealDate; | ||
| } | ||
| // TODO: this is not needed in Vite 7.2+ | ||
| class VitestEvaluatedModules extends EvaluatedModules { | ||
| getModuleSourceMapById(id) { | ||
| const map = super.getModuleSourceMapById(id); | ||
| if (map != null && !("_patched" in map)) { | ||
| map._patched = true; | ||
| const dir = dirname(map.url); | ||
| map.resolvedSources = (map.map.sources || []).map((s) => resolve(dir, s || "")); | ||
| } | ||
| return map; | ||
| } | ||
| } | ||
| const { get } = Reflect; | ||
| function withSafeTimers(fn) { | ||
| const { setTimeout, clearTimeout, nextTick, setImmediate, clearImmediate } = getSafeTimers(); | ||
| const currentSetTimeout = globalThis.setTimeout; | ||
| const currentClearTimeout = globalThis.clearTimeout; | ||
| const currentSetImmediate = globalThis.setImmediate; | ||
| const currentClearImmediate = globalThis.clearImmediate; | ||
| const currentNextTick = globalThis.process?.nextTick; | ||
| try { | ||
| globalThis.setTimeout = setTimeout; | ||
| globalThis.clearTimeout = clearTimeout; | ||
| if (setImmediate) globalThis.setImmediate = setImmediate; | ||
| if (clearImmediate) globalThis.clearImmediate = clearImmediate; | ||
| if (globalThis.process && nextTick) globalThis.process.nextTick = nextTick; | ||
| return fn(); | ||
| } finally { | ||
| globalThis.setTimeout = currentSetTimeout; | ||
| globalThis.clearTimeout = currentClearTimeout; | ||
| globalThis.setImmediate = currentSetImmediate; | ||
| globalThis.clearImmediate = currentClearImmediate; | ||
| if (globalThis.process && nextTick) nextTick(() => { | ||
| globalThis.process.nextTick = currentNextTick; | ||
| }); | ||
| } | ||
| } | ||
| const promises = /* @__PURE__ */ new Set(); | ||
| async function rpcDone() { | ||
| if (!promises.size) return; | ||
| const awaitable = Array.from(promises); | ||
| return Promise.all(awaitable); | ||
| } | ||
| const onCancelCallbacks = []; | ||
| function onCancel(callback) { | ||
| onCancelCallbacks.push(callback); | ||
| } | ||
| function createRuntimeRpc(options) { | ||
| return createSafeRpc(createBirpc({ async onCancel(reason) { | ||
| await Promise.all(onCancelCallbacks.map((fn) => fn(reason))); | ||
| } }, { | ||
| eventNames: ["onCancel"], | ||
| timeout: -1, | ||
| ...options | ||
| })); | ||
| } | ||
| function createSafeRpc(rpc) { | ||
| return new Proxy(rpc, { get(target, p, handler) { | ||
| // keep $rejectPendingCalls as sync function | ||
| if (p === "$rejectPendingCalls") return rpc.$rejectPendingCalls; | ||
| const sendCall = get(target, p, handler); | ||
| const safeSendCall = (...args) => withSafeTimers(async () => { | ||
| const result = sendCall(...args); | ||
| promises.add(result); | ||
| try { | ||
| return await result; | ||
| } finally { | ||
| promises.delete(result); | ||
| } | ||
| }); | ||
| safeSendCall.asEvent = sendCall.asEvent; | ||
| return safeSendCall; | ||
| } }); | ||
| } | ||
| function rpc() { | ||
| const { rpc } = getWorkerState(); | ||
| return rpc; | ||
| } | ||
| export { RealDate as R, VitestEvaluatedModules as V, rpcDone as a, resetDate as b, createRuntimeRpc as c, mockDate as m, onCancel as o, rpc as r }; |
| import { r as resolveCoverageProviderModule } from './coverage.CTzCuANN.js'; | ||
| import { setSafeTimers } from '@vitest/utils/timers'; | ||
| import { g as getWorkerState } from './utils.DYj33du9.js'; | ||
| import { a as addSerializer } from './plugins.DrsmdUE2.js'; | ||
| async function startCoverageInsideWorker(options, loader, runtimeOptions) { | ||
| const coverageModule = await resolveCoverageProviderModule(options, loader); | ||
| if (coverageModule) return coverageModule.startCoverage?.({ | ||
| ...runtimeOptions, | ||
| autoAttachSubprocess: options.autoAttachSubprocess, | ||
| reportsDirectory: options.reportsDirectory | ||
| }); | ||
| return null; | ||
| } | ||
| async function takeCoverageInsideWorker(options, loader) { | ||
| const coverageModule = await resolveCoverageProviderModule(options, loader); | ||
| if (coverageModule) return coverageModule.takeCoverage?.({ moduleExecutionInfo: loader.moduleExecutionInfo }); | ||
| return null; | ||
| } | ||
| async function stopCoverageInsideWorker(options, loader, runtimeOptions) { | ||
| const coverageModule = await resolveCoverageProviderModule(options, loader); | ||
| if (coverageModule) return coverageModule.stopCoverage?.(runtimeOptions); | ||
| return null; | ||
| } | ||
| let globalSetup = false; | ||
| async function setupCommonEnv(config) { | ||
| setupDefines(config); | ||
| setupEnv(config.env); | ||
| if (globalSetup) return; | ||
| globalSetup = true; | ||
| setSafeTimers(); | ||
| if (config.globals) (await import('./globals.CzUA1xn8.js')).registerApiGlobally(); | ||
| } | ||
| function setupDefines(config) { | ||
| for (const key in config.defines) globalThis[key] = config.defines[key]; | ||
| } | ||
| function setupEnv(env) { | ||
| const state = getWorkerState(); | ||
| // same boolean-to-string assignment as VitestPlugin.configResolved | ||
| const { PROD, DEV, ...restEnvs } = env; | ||
| state.metaEnv.PROD = PROD; | ||
| state.metaEnv.DEV = DEV; | ||
| for (const key in restEnvs) state.metaEnv[key] = env[key]; | ||
| } | ||
| async function loadDiffConfig(config, moduleRunner) { | ||
| if (typeof config.diff === "object") return config.diff; | ||
| if (typeof config.diff !== "string") return; | ||
| const diffModule = await moduleRunner.import(config.diff); | ||
| if (diffModule && typeof diffModule.default === "object" && diffModule.default != null) return diffModule.default; | ||
| else throw new Error(`invalid diff config file ${config.diff}. Must have a default export with config object`); | ||
| } | ||
| async function loadSnapshotSerializers(config, moduleRunner) { | ||
| const files = config.snapshotSerializers; | ||
| (await Promise.all(files.map(async (file) => { | ||
| const mo = await moduleRunner.import(file); | ||
| if (!mo || typeof mo.default !== "object" || mo.default === null) throw new Error(`invalid snapshot serializer file ${file}. Must export a default object`); | ||
| const config = mo.default; | ||
| if (typeof config.test !== "function" || typeof config.serialize !== "function" && typeof config.print !== "function") throw new TypeError(`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`); | ||
| return config; | ||
| }))).forEach((serializer) => addSerializer(serializer)); | ||
| } | ||
| export { loadSnapshotSerializers as a, startCoverageInsideWorker as b, stopCoverageInsideWorker as c, loadDiffConfig as l, setupCommonEnv as s, takeCoverageInsideWorker as t }; |
| import { aE as SnapshotState, d as Test, aF as PromisifyAssertion, aG as Tester, H as BenchResult, F as File } from './config.d.CKWK3nld.js'; | ||
| import { Plugin } from '@vitest/pretty-format'; | ||
| interface SnapshotMatcher<T> { | ||
| <U extends { [P in keyof T] : any }>(snapshot: Partial<U>, hint?: string): void; | ||
| (hint?: string): void; | ||
| } | ||
| interface InlineSnapshotMatcher<T> { | ||
| <U extends { [P in keyof T] : any }>(properties: Partial<U>, snapshot?: string, hint?: string): void; | ||
| (hint?: string): void; | ||
| } | ||
| declare module "vitest" { | ||
| interface MatcherState { | ||
| environment: string; | ||
| snapshotState: SnapshotState; | ||
| task?: Readonly<Test>; | ||
| } | ||
| interface ExpectPollOptions { | ||
| interval?: number; | ||
| timeout?: number; | ||
| message?: string; | ||
| } | ||
| interface ExpectStatic { | ||
| assert: Chai.AssertStatic; | ||
| unreachable: (message?: string) => never; | ||
| soft: <T>(actual: T, message?: string) => Assertion<T>; | ||
| poll: <T>(actual: (options: { | ||
| signal: AbortSignal; | ||
| }) => T, options?: ExpectPollOptions) => PromisifyAssertion<Awaited<T>>; | ||
| addEqualityTesters: (testers: Array<Tester>) => void; | ||
| assertions: (expected: number) => void; | ||
| hasAssertions: () => void; | ||
| addSnapshotSerializer: (plugin: Plugin) => void; | ||
| } | ||
| interface Assertion<T> { | ||
| matchSnapshot: SnapshotMatcher<T>; | ||
| toMatchSnapshot: SnapshotMatcher<T>; | ||
| toMatchInlineSnapshot: InlineSnapshotMatcher<T>; | ||
| /** | ||
| * Checks that an error thrown by a function matches a previously recorded snapshot. | ||
| * | ||
| * @param hint - Optional custom error message. | ||
| * | ||
| * @example | ||
| * expect(functionWithError).toThrowErrorMatchingSnapshot(); | ||
| */ | ||
| toThrowErrorMatchingSnapshot: (hint?: string) => void; | ||
| /** | ||
| * Checks that an error thrown by a function matches an inline snapshot within the test file. | ||
| * Useful for keeping snapshots close to the test code. | ||
| * | ||
| * @param snapshot - Optional inline snapshot string to match. | ||
| * @param hint - Optional custom error message. | ||
| * | ||
| * @example | ||
| * const throwError = () => { throw new Error('Error occurred') }; | ||
| * expect(throwError).toThrowErrorMatchingInlineSnapshot(`"Error occurred"`); | ||
| */ | ||
| toThrowErrorMatchingInlineSnapshot: (snapshot?: string, hint?: string) => void; | ||
| /** | ||
| * Compares the received value to a snapshot saved in a specified file. | ||
| * Useful for cases where snapshot content is large or needs to be shared across tests. | ||
| * | ||
| * @param filepath - Path to the snapshot file. | ||
| * @param hint - Optional custom error message. | ||
| * | ||
| * @example | ||
| * await expect(largeData).toMatchFileSnapshot('path/to/snapshot.json'); | ||
| */ | ||
| toMatchFileSnapshot: (filepath: string, hint?: string) => Promise<void>; | ||
| /** | ||
| * Asserts that a benchmark result is faster than another benchmark result. | ||
| * Compares mean latency — lower is faster. | ||
| * | ||
| * @example | ||
| * const result = await bench.compare( | ||
| * bench('lib1', () => { lib1() }), | ||
| * bench('lib2', () => { lib2() }), | ||
| * ) | ||
| * expect(result.get('lib1')).toBeFasterThan(result.get('lib2')) | ||
| * expect(result.get('lib1')).toBeFasterThan(result.get('lib2'), { delta: 0.1 }) | ||
| */ | ||
| toBeFasterThan: (expected: BenchResult, options?: { | ||
| delta?: number; | ||
| }) => void; | ||
| /** | ||
| * Asserts that a benchmark result is slower than another benchmark result. | ||
| * Compares mean latency — higher is slower. | ||
| * | ||
| * @example | ||
| * const result = await bench.compare( | ||
| * bench('lib1', () => { lib1() }), | ||
| * bench('lib2', () => { lib2() }), | ||
| * ) | ||
| * expect(result.get('lib2')).toBeSlowerThan(result.get('lib1')) | ||
| * expect(result.get('lib2')).toBeSlowerThan(result.get('lib1'), { delta: 0.2 }) | ||
| */ | ||
| toBeSlowerThan: (expected: BenchResult, options?: { | ||
| delta?: number; | ||
| }) => void; | ||
| /** | ||
| * Ensures a `vi.when` chain has been exhausted. | ||
| * | ||
| * A chain is exhausted when at least one `calledWith` with an associated action (`then*`) has been registered | ||
| * and every registered behavior has been fully consumed. A chain with no registered | ||
| * behaviors, or with `calledWith` entries that have no associated `then*` actions, is never considered exhausted. | ||
| * | ||
| * @see {@link https://vitest.dev/api/expect#tohavebeenexhausted} | ||
| * | ||
| * @example | ||
| * const w = vi.when(spy).calledWith('hello').thenReturnOnce('HELLO') | ||
| * | ||
| * expect(w).not.toHaveBeenExhausted() | ||
| * | ||
| * expect(spy('hello')).toBe('HELLO') | ||
| * | ||
| * expect(w).toHaveBeenExhausted() | ||
| */ | ||
| toHaveBeenExhausted: () => void; | ||
| } | ||
| } | ||
| interface HashMeta { | ||
| typecheck?: boolean; | ||
| __vitest_label__?: string; | ||
| } | ||
| declare function createFileTask(filepath: string, root: string, projectName: string | undefined, pool?: string, viteEnvironment?: string, meta?: HashMeta): File; | ||
| /** | ||
| * Generate a unique ID for a file based on its path and project name | ||
| * @param file File relative to the root of the project to keep ID the same between different machines | ||
| * @param projectName The name of the test project | ||
| */ | ||
| declare function generateFileHash(file: string, projectName: string | undefined, meta?: HashMeta): string; | ||
| export { createFileTask as c, generateFileHash as g }; |
| import { stripVTControlCharacters } from 'node:util'; | ||
| import { truncateString as truncateString$1 } from '@vitest/utils/display'; | ||
| import { slash } from '@vitest/utils/helpers'; | ||
| import { isAbsolute, relative, dirname, basename } from 'pathe'; | ||
| import c from 'tinyrainbow'; | ||
| const F_RIGHT = "→"; | ||
| const F_DOWN = "↓"; | ||
| const F_DOWN_RIGHT = "↳"; | ||
| const F_POINTER = "❯"; | ||
| const F_DOT = "·"; | ||
| const F_CHECK = "✓"; | ||
| const F_CROSS = "×"; | ||
| const F_LONG_DASH = "⎯"; | ||
| const F_TODO = "□"; | ||
| const F_TREE_NODE_MIDDLE = "├──"; | ||
| const F_TREE_NODE_END = "└──"; | ||
| const pointer = c.yellow(F_POINTER); | ||
| const skipped = c.dim(c.gray(F_DOWN)); | ||
| const todo = c.dim(c.gray(F_TODO)); | ||
| const benchmarkPass = c.green(F_DOT); | ||
| const testPass = c.green(F_CHECK); | ||
| const taskFail = c.red(F_CROSS); | ||
| const suiteFail = c.red(F_POINTER); | ||
| const pending = c.gray("·"); | ||
| const separator = c.dim(" > "); | ||
| const labelDefaultColors = [ | ||
| c.bgYellow, | ||
| c.bgCyan, | ||
| c.bgGreen, | ||
| c.bgMagenta | ||
| ]; | ||
| function getCols(delta = 0) { | ||
| let length = process.stdout?.columns; | ||
| if (!length || Number.isNaN(length)) length = 30; | ||
| return Math.max(length + delta, 0); | ||
| } | ||
| function errorBanner(message) { | ||
| return divider(c.bold(c.bgRed(` ${message} `)), null, null, c.red); | ||
| } | ||
| function divider(text, left, right, color) { | ||
| const cols = getCols(); | ||
| const c = color || ((text) => text); | ||
| if (text) { | ||
| const textLength = stripVTControlCharacters(text).length; | ||
| if (left == null && right != null) left = cols - textLength - right; | ||
| else { | ||
| left = left ?? Math.floor((cols - textLength) / 2); | ||
| right = cols - textLength - left; | ||
| } | ||
| left = Math.max(0, left); | ||
| right = Math.max(0, right); | ||
| return `${c(F_LONG_DASH.repeat(left))}${text}${c(F_LONG_DASH.repeat(right))}`; | ||
| } | ||
| return F_LONG_DASH.repeat(cols); | ||
| } | ||
| function formatTestPath(root, path) { | ||
| if (isAbsolute(path)) path = relative(root, path); | ||
| const dir = dirname(path); | ||
| const ext = path.match(/(\.(spec|test)\.[cm]?[tj]sx?)$/)?.[0] || ""; | ||
| const base = basename(path, ext); | ||
| return slash(c.dim(`${dir}/`) + c.bold(base)) + c.dim(ext); | ||
| } | ||
| function renderSnapshotSummary(rootDir, snapshots) { | ||
| const summary = []; | ||
| if (snapshots.added) summary.push(c.bold(c.green(`${snapshots.added} written`))); | ||
| if (snapshots.unmatched) summary.push(c.bold(c.red(`${snapshots.unmatched} failed`))); | ||
| if (snapshots.updated) summary.push(c.bold(c.green(`${snapshots.updated} updated `))); | ||
| if (snapshots.filesRemoved) if (snapshots.didUpdate) summary.push(c.bold(c.green(`${snapshots.filesRemoved} files removed `))); | ||
| else summary.push(c.bold(c.yellow(`${snapshots.filesRemoved} files obsolete `))); | ||
| if (snapshots.filesRemovedList && snapshots.filesRemovedList.length) { | ||
| const [head, ...tail] = snapshots.filesRemovedList; | ||
| summary.push(`${c.gray(F_DOWN_RIGHT)} ${formatTestPath(rootDir, head)}`); | ||
| tail.forEach((key) => { | ||
| summary.push(` ${c.gray(F_DOT)} ${formatTestPath(rootDir, key)}`); | ||
| }); | ||
| } | ||
| if (snapshots.unchecked) { | ||
| if (snapshots.didUpdate) summary.push(c.bold(c.green(`${snapshots.unchecked} removed`))); | ||
| else summary.push(c.bold(c.yellow(`${snapshots.unchecked} obsolete`))); | ||
| snapshots.uncheckedKeysByFile.forEach((uncheckedFile) => { | ||
| summary.push(`${c.gray(F_DOWN_RIGHT)} ${formatTestPath(rootDir, uncheckedFile.filePath)}`); | ||
| uncheckedFile.keys.forEach((key) => summary.push(` ${c.gray(F_DOT)} ${key}`)); | ||
| }); | ||
| } | ||
| return summary; | ||
| } | ||
| function countTestErrors(tasks) { | ||
| return tasks.reduce((c, i) => c + (i.result?.errors?.length || 0), 0); | ||
| } | ||
| function getStateString(tasks, name = "tests", showTotal = true) { | ||
| if (tasks.length === 0) return c.dim(`no ${name}`); | ||
| const passed = tasks.reduce((acc, i) => { | ||
| // Exclude expected failures from passed count | ||
| if (i.result?.state === "pass" && i.type === "test" && i.fails) return acc; | ||
| return i.result?.state === "pass" ? acc + 1 : acc; | ||
| }, 0); | ||
| const failed = tasks.reduce((acc, i) => i.result?.state === "fail" ? acc + 1 : acc, 0); | ||
| const skipped = tasks.reduce((acc, i) => i.mode === "skip" ? acc + 1 : acc, 0); | ||
| const todo = tasks.reduce((acc, i) => i.mode === "todo" ? acc + 1 : acc, 0); | ||
| const expectedFail = tasks.reduce((acc, i) => { | ||
| // Count tests that are marked as .fails and passed (which means they failed as expected) | ||
| if (i.result?.state === "pass" && i.type === "test" && i.fails) return acc + 1; | ||
| return acc; | ||
| }, 0); | ||
| return [ | ||
| failed ? c.bold(c.red(`${failed} failed`)) : null, | ||
| passed ? c.bold(c.green(`${passed} passed`)) : null, | ||
| expectedFail ? c.cyan(`${expectedFail} expected fail`) : null, | ||
| skipped ? c.yellow(`${skipped} skipped`) : null, | ||
| todo ? c.gray(`${todo} todo`) : null | ||
| ].filter(Boolean).join(c.dim(" | ")) + (showTotal ? c.gray(` (${tasks.length})`) : ""); | ||
| } | ||
| function getStateSymbol(task) { | ||
| if (task.mode === "todo") return todo; | ||
| if (task.mode === "skip") return skipped; | ||
| if (!task.result) return pending; | ||
| if (task.result.state === "run" || task.result.state === "queued") { | ||
| if (task.type === "suite") return pointer; | ||
| } | ||
| if (task.result.state === "pass") return task.meta?.benchmark ? benchmarkPass : testPass; | ||
| if (task.result.state === "fail") return task.type === "suite" ? suiteFail : taskFail; | ||
| return " "; | ||
| } | ||
| function formatTimeString(date) { | ||
| return date.toTimeString().split(" ")[0]; | ||
| } | ||
| function formatTime(time) { | ||
| if (time > 1e3) return `${(time / 1e3).toFixed(2)}s`; | ||
| return `${Math.round(time)}ms`; | ||
| } | ||
| function formatProjectName(project, suffix = " ") { | ||
| if (!project?.name) return ""; | ||
| if (!c.isColorSupported) return `|${project.name}|${suffix}`; | ||
| let background = project.color && c[`bg${capitalize(project.color)}`]; | ||
| if (!background) background = labelDefaultColors[project.name.split("").reduce((acc, v, idx) => acc + v.charCodeAt(0) + idx, 0) % labelDefaultColors.length]; | ||
| return c.black(background(` ${project.name} `)) + suffix; | ||
| } | ||
| function withLabel(color, label, message) { | ||
| const bgColor = `bg${color.charAt(0).toUpperCase()}${color.slice(1)}`; | ||
| return `${c.bold(c.black(c[bgColor](` ${label} `)))} ${message ? c[color](message) : ""}`; | ||
| } | ||
| function padSummaryTitle(str) { | ||
| return c.dim(`${str.padStart(11)} `); | ||
| } | ||
| function truncateString(text, maxLength) { | ||
| return truncateString$1(stripVTControlCharacters(text), maxLength); | ||
| } | ||
| function capitalize(text) { | ||
| return `${text[0].toUpperCase()}${text.slice(1)}`; | ||
| } | ||
| /** | ||
| * Returns the singular or plural form of a word based on the count. | ||
| */ | ||
| function noun(count, singular, plural) { | ||
| if (count === 1) return singular; | ||
| return plural; | ||
| } | ||
| var utils = /*#__PURE__*/Object.freeze({ | ||
| __proto__: null, | ||
| benchmarkPass: benchmarkPass, | ||
| countTestErrors: countTestErrors, | ||
| divider: divider, | ||
| errorBanner: errorBanner, | ||
| formatProjectName: formatProjectName, | ||
| formatTestPath: formatTestPath, | ||
| formatTime: formatTime, | ||
| formatTimeString: formatTimeString, | ||
| getStateString: getStateString, | ||
| getStateSymbol: getStateSymbol, | ||
| noun: noun, | ||
| padSummaryTitle: padSummaryTitle, | ||
| pending: pending, | ||
| pointer: pointer, | ||
| renderSnapshotSummary: renderSnapshotSummary, | ||
| separator: separator, | ||
| skipped: skipped, | ||
| suiteFail: suiteFail, | ||
| taskFail: taskFail, | ||
| testPass: testPass, | ||
| todo: todo, | ||
| truncateString: truncateString, | ||
| withLabel: withLabel | ||
| }); | ||
| export { F_POINTER as F, formatTimeString as a, taskFail as b, F_CHECK as c, divider as d, errorBanner as e, formatProjectName as f, F_DOWN_RIGHT as g, getStateSymbol as h, getStateString as i, formatTime as j, countTestErrors as k, F_TREE_NODE_END as l, F_TREE_NODE_MIDDLE as m, noun as n, F_RIGHT as o, padSummaryTitle as p, renderSnapshotSummary as r, separator as s, truncateString as t, utils as u, withLabel as w }; |
| import { fileURLToPath, pathToFileURL } from 'node:url'; | ||
| import vm, { isContext, runInContext } from 'node:vm'; | ||
| import { dirname, basename, extname, normalize, resolve } from 'pathe'; | ||
| import { l as loadEnvironment, a as listenForErrors, e as emitModuleRunner } from './init.DTAQFCjl.js'; | ||
| import { distDir } from '../path.js'; | ||
| import { createCustomConsole } from './console.DjVIMaXT.js'; | ||
| import fs__default from 'node:fs'; | ||
| import { createRequire, Module, isBuiltin } from 'node:module'; | ||
| import { toArray, splitFileAndPostfix, isBareImport } from '@vitest/utils/helpers'; | ||
| import { findNearestPackageData } from '@vitest/utils/resolver'; | ||
| import { dirname as dirname$1 } from 'node:path'; | ||
| import { CSS_LANGS_RE, KNOWN_ASSET_RE } from '@vitest/utils/constants'; | ||
| import { getDefaultRequestStubs } from '../module-evaluator.js'; | ||
| import { s as startVitestModuleRunner, V as VITEST_VM_CONTEXT_SYMBOL, c as createNodeImportMeta } from './index.DNRmy2jU.js'; | ||
| import { p as provideWorkerState } from './utils.DYj33du9.js'; | ||
| function interopCommonJsModule(interopDefault, mod) { | ||
| if (isPrimitive(mod) || Array.isArray(mod) || mod instanceof Promise) return { | ||
| keys: [], | ||
| moduleExports: {}, | ||
| defaultExport: mod | ||
| }; | ||
| if (interopDefault !== false && "__esModule" in mod && !isPrimitive(mod.default)) { | ||
| const defaultKets = Object.keys(mod.default); | ||
| const moduleKeys = Object.keys(mod); | ||
| const allKeys = new Set([...defaultKets, ...moduleKeys]); | ||
| allKeys.delete("default"); | ||
| return { | ||
| keys: Array.from(allKeys), | ||
| moduleExports: new Proxy(mod, { get(mod, prop) { | ||
| return mod[prop] ?? mod.default?.[prop]; | ||
| } }), | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| return { | ||
| keys: Object.keys(mod).filter((key) => key !== "default"), | ||
| moduleExports: mod, | ||
| defaultExport: mod | ||
| }; | ||
| } | ||
| function isPrimitive(obj) { | ||
| return !(obj != null && (typeof obj === "object" || typeof obj === "function")); | ||
| } | ||
| const SyntheticModule = vm.SyntheticModule; | ||
| const SourceTextModule = vm.SourceTextModule; | ||
| const _require = createRequire(import.meta.url); | ||
| const requiresCache = /* @__PURE__ */ new WeakMap(); | ||
| class CommonjsExecutor { | ||
| context; | ||
| requireCache = /* @__PURE__ */ new Map(); | ||
| publicRequireCache = this.createProxyCache(); | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| builtinCache = Object.create(null); | ||
| extensions = Object.create(null); | ||
| fs; | ||
| Module; | ||
| interopDefault; | ||
| constructor(options) { | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.interopDefault = options.interopDefault; | ||
| const primitives = vm.runInContext("({ Object, Array, Error })", this.context); | ||
| // eslint-disable-next-line ts/no-this-alias | ||
| const executor = this; | ||
| this.Module = class Module$1 { | ||
| exports; | ||
| isPreloading = false; | ||
| id; | ||
| filename; | ||
| loaded; | ||
| parent; | ||
| children = []; | ||
| path; | ||
| paths = []; | ||
| constructor(id = "", parent) { | ||
| this.exports = primitives.Object.create(Object.prototype); | ||
| // in our case the path should always be resolved already | ||
| this.path = dirname(id); | ||
| this.id = id; | ||
| this.filename = id; | ||
| this.loaded = false; | ||
| this.parent = parent; | ||
| } | ||
| get require() { | ||
| const require = requiresCache.get(this); | ||
| if (require) return require; | ||
| const _require = Module$1.createRequire(this.id); | ||
| requiresCache.set(this, _require); | ||
| return _require; | ||
| } | ||
| static getSourceMapsSupport = () => ({ | ||
| enabled: false, | ||
| nodeModules: false, | ||
| generatedCode: false | ||
| }); | ||
| static setSourceMapsSupport = () => { | ||
| // noop | ||
| }; | ||
| static register = () => { | ||
| throw new Error(`[vitest] "register" is not available when running in Vitest.`); | ||
| }; | ||
| static registerHooks = () => { | ||
| throw new Error(`[vitest] "registerHooks" is not available when running in Vitest.`); | ||
| }; | ||
| _compile(code, filename) { | ||
| const cjsModule = Module$1.wrap(code); | ||
| const script = new vm.Script(cjsModule, { | ||
| filename, | ||
| importModuleDynamically: options.importModuleDynamically | ||
| }); | ||
| // @ts-expect-error mark script with current identifier | ||
| script.identifier = filename; | ||
| const fn = script.runInContext(executor.context); | ||
| const __dirname = dirname(filename); | ||
| executor.requireCache.set(filename, this); | ||
| try { | ||
| fn(this.exports, this.require, this, filename, __dirname); | ||
| return this.exports; | ||
| } finally { | ||
| this.loaded = true; | ||
| } | ||
| } | ||
| // exposed for external use, Node.js does the opposite | ||
| static _load = (request, parent, _isMain) => { | ||
| return Module$1.createRequire(parent?.filename ?? request)(request); | ||
| }; | ||
| static wrap = (script) => { | ||
| return Module$1.wrapper[0] + script + Module$1.wrapper[1]; | ||
| }; | ||
| static wrapper = new primitives.Array("(function (exports, require, module, __filename, __dirname) { ", "\n});"); | ||
| static builtinModules = Module.builtinModules; | ||
| static findSourceMap = Module.findSourceMap; | ||
| static SourceMap = Module.SourceMap; | ||
| static syncBuiltinESMExports = Module.syncBuiltinESMExports; | ||
| static _cache = executor.publicRequireCache; | ||
| static _extensions = executor.extensions; | ||
| static createRequire = (filename) => { | ||
| return executor.createRequire(filename); | ||
| }; | ||
| static runMain = () => { | ||
| throw new primitives.Error("[vitest] \"runMain\" is not implemented."); | ||
| }; | ||
| // @ts-expect-error not typed | ||
| static _resolveFilename = Module._resolveFilename; | ||
| // @ts-expect-error not typed | ||
| static _findPath = Module._findPath; | ||
| // @ts-expect-error not typed | ||
| static _initPaths = Module._initPaths; | ||
| // @ts-expect-error not typed | ||
| static _preloadModules = Module._preloadModules; | ||
| // @ts-expect-error not typed | ||
| static _resolveLookupPaths = Module._resolveLookupPaths; | ||
| // @ts-expect-error not typed | ||
| static globalPaths = Module.globalPaths; | ||
| static isBuiltin = Module.isBuiltin; | ||
| static constants = Module.constants; | ||
| static enableCompileCache = Module.enableCompileCache; | ||
| static getCompileCacheDir = Module.getCompileCacheDir; | ||
| static flushCompileCache = Module.flushCompileCache; | ||
| static stripTypeScriptTypes = Module.stripTypeScriptTypes; | ||
| static findPackageJSON = Module.findPackageJSON; | ||
| static Module = Module$1; | ||
| }; | ||
| this.extensions[".js"] = this.requireJs; | ||
| this.extensions[".json"] = this.requireJson; | ||
| } | ||
| requireJs = (m, filename) => { | ||
| const content = this.fs.readFile(filename); | ||
| m._compile(content, filename); | ||
| }; | ||
| requireJson = (m, filename) => { | ||
| const code = this.fs.readFile(filename); | ||
| m.exports = JSON.parse(code); | ||
| }; | ||
| static cjsConditions; | ||
| static getCjsConditions() { | ||
| if (!CommonjsExecutor.cjsConditions) CommonjsExecutor.cjsConditions = parseCjsConditions(process.execArgv, process.env.NODE_OPTIONS); | ||
| return CommonjsExecutor.cjsConditions; | ||
| } | ||
| createRequire = (filename) => { | ||
| const _require = createRequire(filename); | ||
| const resolve = (id, options) => { | ||
| return _require.resolve(id, { | ||
| ...options, | ||
| conditions: CommonjsExecutor.getCjsConditions() | ||
| }); | ||
| }; | ||
| const require = ((id) => { | ||
| const resolved = resolve(id); | ||
| if (extname(resolved) === ".node" || isBuiltin(resolved)) return this.requireCoreModule(resolved); | ||
| const module = new this.Module(resolved); | ||
| return this.loadCommonJSModule(module, resolved); | ||
| }); | ||
| require.resolve = resolve; | ||
| require.resolve.paths = _require.resolve.paths; | ||
| Object.defineProperty(require, "extensions", { | ||
| get: () => this.extensions, | ||
| set: () => {}, | ||
| configurable: true | ||
| }); | ||
| require.main = void 0; | ||
| require.cache = this.publicRequireCache; | ||
| return require; | ||
| }; | ||
| createProxyCache() { | ||
| return new Proxy(Object.create(null), { | ||
| defineProperty: () => true, | ||
| deleteProperty: () => true, | ||
| set: () => true, | ||
| get: (_, key) => this.requireCache.get(key), | ||
| has: (_, key) => this.requireCache.has(key), | ||
| ownKeys: () => Array.from(this.requireCache.keys()), | ||
| getOwnPropertyDescriptor() { | ||
| return { | ||
| configurable: true, | ||
| enumerable: true | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| // very naive implementation for Node.js require | ||
| loadCommonJSModule(module, filename) { | ||
| const cached = this.requireCache.get(filename); | ||
| if (cached) return cached.exports; | ||
| const extension = this.findLongestRegisteredExtension(filename); | ||
| (this.extensions[extension] || this.extensions[".js"])(module, filename); | ||
| return module.exports; | ||
| } | ||
| findLongestRegisteredExtension(filename) { | ||
| const name = basename(filename); | ||
| let currentExtension; | ||
| let index; | ||
| let startIndex = 0; | ||
| // eslint-disable-next-line no-cond-assign | ||
| while ((index = name.indexOf(".", startIndex)) !== -1) { | ||
| startIndex = index + 1; | ||
| if (index === 0) continue; | ||
| currentExtension = name.slice(index); | ||
| if (this.extensions[currentExtension]) return currentExtension; | ||
| } | ||
| return ".js"; | ||
| } | ||
| getCoreSyntheticModule(identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(identifier); | ||
| const keys = Object.keys(exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], () => { | ||
| for (const key of keys) module.setExport(key, exports$1[key]); | ||
| module.setExport("default", exports$1); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| getCjsSyntheticModule(path, identifier) { | ||
| if (this.moduleCache.has(identifier)) return this.moduleCache.get(identifier); | ||
| const exports$1 = this.require(path); | ||
| // TODO: technically module should be parsed to find static exports, implement for strict mode in #2854 | ||
| const { keys, moduleExports, defaultExport } = interopCommonJsModule(this.interopDefault, exports$1); | ||
| const module = new SyntheticModule([...keys, "default"], function() { | ||
| for (const key of keys) this.setExport(key, moduleExports[key]); | ||
| this.setExport("default", defaultExport); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| // TODO: use this in strict mode, when available in #2854 | ||
| // private _getNamedCjsExports(path: string): Set<string> { | ||
| // const cachedNamedExports = this.cjsNamedExportsMap.get(path) | ||
| // if (cachedNamedExports) { | ||
| // return cachedNamedExports | ||
| // } | ||
| // if (extname(path) === '.node') { | ||
| // const moduleExports = this.require(path) | ||
| // const namedExports = new Set(Object.keys(moduleExports)) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // return namedExports | ||
| // } | ||
| // const code = this.fs.readFile(path) | ||
| // const { exports, reexports } = parseCjs(code, path) | ||
| // const namedExports = new Set(exports) | ||
| // this.cjsNamedExportsMap.set(path, namedExports) | ||
| // for (const reexport of reexports) { | ||
| // if (isNodeBuiltin(reexport)) { | ||
| // const exports = this.require(reexport) | ||
| // if (exports !== null && typeof exports === 'object') { | ||
| // for (const e of Object.keys(exports)) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // else { | ||
| // const require = this.createRequire(path) | ||
| // const resolved = require.resolve(reexport) | ||
| // const exports = this._getNamedCjsExports(resolved) | ||
| // for (const e of exports) { | ||
| // namedExports.add(e) | ||
| // } | ||
| // } | ||
| // } | ||
| // return namedExports | ||
| // } | ||
| require(identifier) { | ||
| if (extname(identifier) === ".node" || isBuiltin(identifier)) return this.requireCoreModule(identifier); | ||
| const module = new this.Module(identifier); | ||
| return this.loadCommonJSModule(module, identifier); | ||
| } | ||
| requireCoreModule(identifier) { | ||
| const normalized = identifier.replace(/^node:/, ""); | ||
| if (this.builtinCache[normalized]) return this.builtinCache[normalized].exports; | ||
| const moduleExports = _require(identifier); | ||
| if (identifier === "node:module" || identifier === "module") { | ||
| const module = new this.Module("/module.js"); | ||
| module.exports = this.Module; | ||
| this.builtinCache[normalized] = module; | ||
| return module.exports; | ||
| } | ||
| this.builtinCache[normalized] = _require.cache[normalized]; | ||
| // TODO: should we wrap module to rethrow context errors? | ||
| return moduleExports; | ||
| } | ||
| } | ||
| // The "module-sync" exports condition (added in Node 22.12/20.19 when | ||
| // require(esm) was unflagged) can resolve to ESM files that our CJS | ||
| // vm.Script executor cannot handle. We exclude it by passing explicit | ||
| // CJS conditions to require.resolve (Node 22.12+). | ||
| // Must be a Set because Node's internal resolver calls conditions.has(). | ||
| // User-specified --conditions/-C flags are respected, except module-sync. | ||
| function parseCjsConditions(execArgv, nodeOptions) { | ||
| const conditions = [ | ||
| "node", | ||
| "require", | ||
| "node-addons" | ||
| ]; | ||
| const args = [...execArgv, ...nodeOptions?.split(/\s+/) ?? []]; | ||
| for (let i = 0; i < args.length; i++) { | ||
| const arg = args[i]; | ||
| const eqMatch = arg.match(/^(?:--conditions|-C)=(.+)$/); | ||
| if (eqMatch) conditions.push(eqMatch[1]); | ||
| else if ((arg === "--conditions" || arg === "-C") && i + 1 < args.length) conditions.push(args[++i]); | ||
| } | ||
| return new Set(conditions.filter((c) => c !== "module-sync")); | ||
| } | ||
| const dataURIRegex = /^data:(?<mime>text\/javascript|application\/json|application\/wasm)(?:;(?<encoding>charset=utf-8|base64))?,(?<code>.*)$/; | ||
| class EsmExecutor { | ||
| moduleCache = /* @__PURE__ */ new Map(); | ||
| esmLinkMap = /* @__PURE__ */ new WeakMap(); | ||
| context; | ||
| #httpIp = IPnumber("127.0.0.0"); | ||
| constructor(executor, options) { | ||
| this.executor = executor; | ||
| this.context = options.context; | ||
| } | ||
| async evaluateModule(m) { | ||
| if (m.status === "unlinked") this.esmLinkMap.set(m, m.link((identifier, referencer) => this.executor.resolveModule(identifier, referencer.identifier))); | ||
| await this.esmLinkMap.get(m); | ||
| if (m.status === "linked") await m.evaluate(); | ||
| return m; | ||
| } | ||
| async createEsModule(fileURL, getCode) { | ||
| const cached = this.moduleCache.get(fileURL); | ||
| if (cached) return cached; | ||
| const promise = this.loadEsModule(fileURL, getCode); | ||
| this.moduleCache.set(fileURL, promise); | ||
| return promise; | ||
| } | ||
| async loadEsModule(fileURL, getCode) { | ||
| const code = await getCode(); | ||
| // TODO: should not be allowed in strict mode, implement in #2854 | ||
| if (fileURL.endsWith(".json")) { | ||
| const m = new SyntheticModule(["default"], function() { | ||
| const result = JSON.parse(code); | ||
| this.setExport("default", result); | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| const m = new SourceTextModule(code, { | ||
| identifier: fileURL, | ||
| context: this.context, | ||
| importModuleDynamically: this.executor.importModuleDynamically, | ||
| initializeImportMeta: (meta, mod) => { | ||
| meta.url = mod.identifier; | ||
| if (mod.identifier.startsWith("file:")) { | ||
| const filename = fileURLToPath(mod.identifier); | ||
| meta.filename = filename; | ||
| meta.dirname = dirname$1(filename); | ||
| } | ||
| meta.resolve = (specifier, importer) => { | ||
| return this.executor.resolve(specifier, importer != null ? importer.toString() : mod.identifier); | ||
| }; | ||
| } | ||
| }); | ||
| this.moduleCache.set(fileURL, m); | ||
| return m; | ||
| } | ||
| async createWebAssemblyModule(fileUrl, getCode) { | ||
| const cached = this.moduleCache.get(fileUrl); | ||
| if (cached) return cached; | ||
| const m = this.loadWebAssemblyModule(getCode(), fileUrl); | ||
| this.moduleCache.set(fileUrl, m); | ||
| return m; | ||
| } | ||
| async createNetworkModule(fileUrl) { | ||
| // https://nodejs.org/api/esm.html#https-and-http-imports | ||
| if (fileUrl.startsWith("http:")) { | ||
| const url = new URL(fileUrl); | ||
| if (url.hostname !== "localhost" && url.hostname !== "::1" && (IPnumber(url.hostname) & IPmask(8)) !== this.#httpIp) throw new Error( | ||
| // we don't know the importer, so it's undefined (the same happens in --pool=threads) | ||
| `import of '${fileUrl}' by undefined is not supported: http can only be used to load local resources (use https instead).` | ||
| ); | ||
| } | ||
| return this.createEsModule(fileUrl, () => fetch(fileUrl).then((r) => r.text())); | ||
| } | ||
| async loadWebAssemblyModule(source, identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const wasmModule = await WebAssembly.compile(source); | ||
| const exports$1 = WebAssembly.Module.exports(wasmModule); | ||
| const imports = WebAssembly.Module.imports(wasmModule); | ||
| const moduleLookup = {}; | ||
| for (const { module } of imports) if (moduleLookup[module] === void 0) moduleLookup[module] = await this.executor.resolveModule(module, identifier); | ||
| const evaluateModule = (module) => this.evaluateModule(module); | ||
| return new SyntheticModule(exports$1.map(({ name }) => name), async function() { | ||
| const importsObject = {}; | ||
| for (const { module, name } of imports) { | ||
| if (!importsObject[module]) importsObject[module] = {}; | ||
| await evaluateModule(moduleLookup[module]); | ||
| importsObject[module][name] = moduleLookup[module].namespace[name]; | ||
| } | ||
| const wasmInstance = new WebAssembly.Instance(wasmModule, importsObject); | ||
| for (const { name } of exports$1) this.setExport(name, wasmInstance.exports[name]); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| } | ||
| cacheModule(identifier, module) { | ||
| this.moduleCache.set(identifier, module); | ||
| } | ||
| resolveCachedModule(identifier) { | ||
| return this.moduleCache.get(identifier); | ||
| } | ||
| async createDataModule(identifier) { | ||
| const cached = this.moduleCache.get(identifier); | ||
| if (cached) return cached; | ||
| const match = identifier.match(dataURIRegex); | ||
| if (!match || !match.groups) throw new Error("Invalid data URI"); | ||
| const mime = match.groups.mime; | ||
| const encoding = match.groups.encoding; | ||
| if (mime === "application/wasm") { | ||
| if (!encoding) throw new Error("Missing data URI encoding"); | ||
| if (encoding !== "base64") throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| const module = this.loadWebAssemblyModule(Buffer.from(match.groups.code, "base64"), identifier); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| let code = match.groups.code; | ||
| if (!encoding || encoding === "charset=utf-8") code = decodeURIComponent(code); | ||
| else if (encoding === "base64") code = Buffer.from(code, "base64").toString(); | ||
| else throw new Error(`Invalid data URI encoding: ${encoding}`); | ||
| if (mime === "application/json") { | ||
| const module = new SyntheticModule(["default"], function() { | ||
| const obj = JSON.parse(code); | ||
| this.setExport("default", obj); | ||
| }, { | ||
| context: this.context, | ||
| identifier | ||
| }); | ||
| this.moduleCache.set(identifier, module); | ||
| return module; | ||
| } | ||
| return this.createEsModule(identifier, () => code); | ||
| } | ||
| } | ||
| function IPnumber(address) { | ||
| const ip = address.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||
| if (ip) return (+ip[1] << 24) + (+ip[2] << 16) + (+ip[3] << 8) + +ip[4]; | ||
| throw new Error(`Expected IP address, received ${address}`); | ||
| } | ||
| function IPmask(maskSize) { | ||
| return -1 << 32 - maskSize; | ||
| } | ||
| const CLIENT_ID = "/@vite/client"; | ||
| const CLIENT_FILE = pathToFileURL(CLIENT_ID).href; | ||
| class ViteExecutor { | ||
| esm; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.esm = options.esmExecutor; | ||
| } | ||
| resolve = (identifier) => { | ||
| if (identifier === CLIENT_ID) return identifier; | ||
| }; | ||
| get workerState() { | ||
| return this.options.context.__vitest_worker__; | ||
| } | ||
| async createViteModule(fileUrl) { | ||
| if (fileUrl === CLIENT_FILE || fileUrl === CLIENT_ID) return this.createViteClientModule(); | ||
| const cached = this.esm.resolveCachedModule(fileUrl); | ||
| if (cached) return cached; | ||
| return this.esm.createEsModule(fileUrl, async () => { | ||
| try { | ||
| const result = await this.options.transform(fileUrl); | ||
| if (result.code) return result.code; | ||
| } catch (cause) { | ||
| // rethrow vite error if it cannot load the module because it's not resolved | ||
| if (typeof cause === "object" && cause.code === "ERR_LOAD_URL" || typeof cause?.message === "string" && cause.message.includes("Failed to load url")) { | ||
| const error = new Error(`Cannot find module '${fileUrl}'`, { cause }); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| } | ||
| throw new Error(`[vitest] Failed to transform ${fileUrl}. Does the file exist?`); | ||
| }); | ||
| } | ||
| createViteClientModule() { | ||
| const identifier = CLIENT_ID; | ||
| const cached = this.esm.resolveCachedModule(identifier); | ||
| if (cached) return cached; | ||
| const stub = this.options.viteClientModule; | ||
| const moduleKeys = Object.keys(stub); | ||
| const module = new SyntheticModule(moduleKeys, function() { | ||
| moduleKeys.forEach((key) => { | ||
| this.setExport(key, stub[key]); | ||
| }); | ||
| }, { | ||
| context: this.options.context, | ||
| identifier | ||
| }); | ||
| this.esm.cacheModule(identifier, module); | ||
| return module; | ||
| } | ||
| canResolve = (fileUrl) => { | ||
| if (fileUrl === CLIENT_FILE) return true; | ||
| const config = this.workerState.config.deps?.web || {}; | ||
| const [modulePath] = fileUrl.split("?"); | ||
| if (config.transformCss && CSS_LANGS_RE.test(modulePath)) return true; | ||
| if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath)) return true; | ||
| if (toArray(config.transformGlobPattern).some((pattern) => pattern.test(modulePath))) return true; | ||
| return false; | ||
| }; | ||
| } | ||
| const { existsSync } = fs__default; | ||
| // always defined when we use vm pool | ||
| const nativeResolve = import.meta.resolve; | ||
| // TODO: improve Node.js strict mode support in #2854 | ||
| class ExternalModulesExecutor { | ||
| cjs; | ||
| esm; | ||
| vite; | ||
| context; | ||
| fs; | ||
| resolvers = []; | ||
| #networkSupported = null; | ||
| constructor(options) { | ||
| this.options = options; | ||
| this.context = options.context; | ||
| this.fs = options.fileMap; | ||
| this.esm = new EsmExecutor(this, { context: this.context }); | ||
| this.cjs = new CommonjsExecutor({ | ||
| context: this.context, | ||
| importModuleDynamically: this.importModuleDynamically, | ||
| fileMap: options.fileMap, | ||
| interopDefault: options.interopDefault | ||
| }); | ||
| this.vite = new ViteExecutor({ | ||
| esmExecutor: this.esm, | ||
| context: this.context, | ||
| transform: options.transform, | ||
| viteClientModule: options.viteClientModule | ||
| }); | ||
| this.resolvers = [this.vite.resolve]; | ||
| } | ||
| async import(identifier) { | ||
| const module = await this.createModule(identifier); | ||
| await this.esm.evaluateModule(module); | ||
| return module.namespace; | ||
| } | ||
| require(identifier) { | ||
| return this.cjs.require(identifier); | ||
| } | ||
| createRequire(identifier) { | ||
| return this.cjs.createRequire(identifier); | ||
| } | ||
| // dynamic import can be used in both ESM and CJS, so we have it in the executor | ||
| importModuleDynamically = async (specifier, referencer) => { | ||
| const module = await this.resolveModule(specifier, referencer.identifier); | ||
| return await this.esm.evaluateModule(module); | ||
| }; | ||
| resolveModule = async (specifier, referencer) => { | ||
| let identifier = this.resolve(specifier, referencer); | ||
| if (identifier instanceof Promise) identifier = await identifier; | ||
| return await this.createModule(identifier); | ||
| }; | ||
| resolve(specifier, parent) { | ||
| for (const resolver of this.resolvers) { | ||
| const id = resolver(specifier, parent); | ||
| if (id) return id; | ||
| } | ||
| // import.meta.resolve can be asynchronous in older +18 Node versions | ||
| return nativeResolve(specifier, parent); | ||
| } | ||
| getModuleInformation(identifier) { | ||
| if (identifier.startsWith("data:")) return { | ||
| type: "data", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const { file, postfix } = splitFileAndPostfix(identifier); | ||
| const extension = extname(file); | ||
| if (extension === ".node" || isBuiltin(identifier)) return { | ||
| type: "builtin", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| if (this.isNetworkSupported && (identifier.startsWith("http:") || identifier.startsWith("https:"))) return { | ||
| type: "network", | ||
| url: identifier, | ||
| path: identifier | ||
| }; | ||
| const isFileUrl = identifier.startsWith("file://"); | ||
| const pathUrl = isFileUrl ? fileURLToPath(file) : file; | ||
| const fileUrl = isFileUrl ? identifier : `${pathToFileURL(file)}${postfix}`; | ||
| let type; | ||
| if (this.vite.canResolve(fileUrl)) type = "vite"; | ||
| else if (extension === ".mjs") type = "module"; | ||
| else if (extension === ".cjs") type = "commonjs"; | ||
| else if (extension === ".wasm") | ||
| // still experimental on NodeJS --experimental-wasm-modules | ||
| // cf. ESM_FILE_FORMAT(url) in https://nodejs.org/docs/latest-v20.x/api/esm.html#resolution-algorithm | ||
| type = "wasm"; | ||
| else type = findNearestPackageData(normalize(pathUrl)).type === "module" ? "module" : "commonjs"; | ||
| return { | ||
| type, | ||
| path: pathUrl, | ||
| url: fileUrl | ||
| }; | ||
| } | ||
| createModule(identifier) { | ||
| const { type, url, path } = this.getModuleInformation(identifier); | ||
| // create ERR_MODULE_NOT_FOUND on our own since latest NodeJS's import.meta.resolve doesn't throw on non-existing namespace or path | ||
| // https://github.com/nodejs/node/pull/49038 | ||
| if ((type === "module" || type === "commonjs" || type === "wasm") && !existsSync(path)) { | ||
| const error = /* @__PURE__ */ new Error(`Cannot find ${isBareImport(path) ? "package" : "module"} '${path}'`); | ||
| error.code = "ERR_MODULE_NOT_FOUND"; | ||
| throw error; | ||
| } | ||
| switch (type) { | ||
| case "data": return this.esm.createDataModule(identifier); | ||
| case "builtin": return this.cjs.getCoreSyntheticModule(identifier); | ||
| case "vite": return this.vite.createViteModule(url); | ||
| case "wasm": return this.esm.createWebAssemblyModule(url, () => this.fs.readBuffer(path)); | ||
| case "module": return this.esm.createEsModule(url, () => this.fs.readFileAsync(path)); | ||
| case "commonjs": return this.cjs.getCjsSyntheticModule(path, identifier); | ||
| case "network": return this.esm.createNetworkModule(url); | ||
| default: return type; | ||
| } | ||
| } | ||
| get isNetworkSupported() { | ||
| if (this.#networkSupported == null) if (process.execArgv.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else if (process.env.NODE_OPTIONS?.includes("--experimental-network-imports")) this.#networkSupported = true; | ||
| else this.#networkSupported = false; | ||
| return this.#networkSupported; | ||
| } | ||
| } | ||
| const { promises, readFileSync } = fs__default; | ||
| class FileMap { | ||
| fsCache = /* @__PURE__ */ new Map(); | ||
| fsBufferCache = /* @__PURE__ */ new Map(); | ||
| async readFileAsync(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = await promises.readFile(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readFile(path) { | ||
| const cached = this.fsCache.get(path); | ||
| if (cached != null) return cached; | ||
| const source = readFileSync(path, "utf-8"); | ||
| this.fsCache.set(path, source); | ||
| return source; | ||
| } | ||
| readBuffer(path) { | ||
| const cached = this.fsBufferCache.get(path); | ||
| if (cached != null) return cached; | ||
| const buffer = readFileSync(path); | ||
| this.fsBufferCache.set(path, buffer); | ||
| return buffer; | ||
| } | ||
| } | ||
| const entryFile = pathToFileURL(resolve(distDir, "workers/runVmTests.js")).href; | ||
| const fileMap = new FileMap(); | ||
| const packageCache = /* @__PURE__ */ new Map(); | ||
| async function runVmTests(method, state, traces) { | ||
| const { ctx, rpc } = state; | ||
| const beforeEnvironmentTime = performance.now(); | ||
| const { environment } = await loadEnvironment(ctx.environment.name, ctx.config.root, rpc, traces, true); | ||
| state.environment = environment; | ||
| if (!environment.setupVM) { | ||
| const envName = ctx.environment.name; | ||
| const packageId = envName[0] === "." ? envName : `vitest-environment-${envName}`; | ||
| throw new TypeError(`Environment "${ctx.environment.name}" is not a valid environment. Path "${packageId}" doesn't support vm environment because it doesn't provide "setupVM" method.`); | ||
| } | ||
| const vm = await traces.$("vitest.runtime.environment.setup", { attributes: { | ||
| "vitest.environment": environment.name, | ||
| "vitest.environment.vite_environment": environment.viteEnvironment || environment.name | ||
| } }, () => environment.setupVM(ctx.environment.options || ctx.config.environmentOptions || {})); | ||
| state.durations.environment = performance.now() - beforeEnvironmentTime; | ||
| process.env.VITEST_VM_POOL = "1"; | ||
| if (!vm.getVmContext) throw new TypeError(`Environment ${environment.name} doesn't provide "getVmContext" method. It should return a context created by "vm.createContext" method.`); | ||
| const context = vm.getVmContext(); | ||
| if (!isContext(context)) throw new TypeError(`Environment ${environment.name} doesn't provide a valid context. It should be created by "vm.createContext" method.`); | ||
| provideWorkerState(context, state); | ||
| // this is unfortunately needed for our own dependencies | ||
| // we need to find a way to not rely on this by default | ||
| // because browser doesn't provide these globals | ||
| context.process = process; | ||
| context.global = context; | ||
| context.console = state.config.disableConsoleIntercept ? console : createCustomConsole(state); | ||
| // TODO: don't hardcode setImmediate in fake timers defaults | ||
| context.setImmediate = setImmediate; | ||
| context.clearImmediate = clearImmediate; | ||
| const stubs = getDefaultRequestStubs(context); | ||
| const externalModulesExecutor = new ExternalModulesExecutor({ | ||
| context, | ||
| fileMap, | ||
| packageCache, | ||
| transform: rpc.transform, | ||
| viteClientModule: stubs["/@vite/client"] | ||
| }); | ||
| process.exit = (code = process.exitCode || 0) => { | ||
| throw new Error(`process.exit unexpectedly called with "${code}"`); | ||
| }; | ||
| listenForErrors(() => state); | ||
| const moduleRunner = startVitestModuleRunner({ | ||
| context, | ||
| evaluatedModules: state.evaluatedModules, | ||
| state, | ||
| externalModulesExecutor, | ||
| createImportMeta: createNodeImportMeta, | ||
| traces | ||
| }); | ||
| emitModuleRunner(moduleRunner); | ||
| Object.defineProperty(context, VITEST_VM_CONTEXT_SYMBOL, { | ||
| value: { | ||
| context, | ||
| externalModulesExecutor | ||
| }, | ||
| configurable: true, | ||
| enumerable: false, | ||
| writable: false | ||
| }); | ||
| context.__vitest_mocker__ = moduleRunner.mocker; | ||
| if (ctx.config.serializedDefines) try { | ||
| runInContext(ctx.config.serializedDefines, context, { filename: "virtual:load-defines.js" }); | ||
| } catch (error) { | ||
| throw new Error(`Failed to load custom "defines": ${error.message}`); | ||
| } | ||
| await moduleRunner.mocker.initializeSpyModule(); | ||
| const { run } = await moduleRunner.import(entryFile); | ||
| try { | ||
| await run(method, ctx.files, ctx.config, moduleRunner, traces); | ||
| } finally { | ||
| await traces.$("vitest.runtime.environment.teardown", () => vm.teardown?.()); | ||
| } | ||
| } | ||
| function setupVmWorker(context) { | ||
| if (context.config.experimental.viteModuleRunner === false) throw new Error(`Pool "${context.pool}" cannot run with "experimental.viteModuleRunner: false". Please, use "threads" or "forks" instead.`); | ||
| } | ||
| export { runVmTests as r, setupVmWorker as s }; |
| import { EvaluatedModules } from 'vite/module-runner'; | ||
| import { aH as FileSpecification, n as SerializedConfig, p as Task, q as CancelReason } from './config.d.CKWK3nld.js'; | ||
| import { a as RuntimeRPC, R as RunnerRPC, G as GetterTracker } from './rpc.d.C6-dGZ2f.js'; | ||
| import { E as Environment } from './environment.d.CrsxCzP1.js'; | ||
| //#region src/messages.d.ts | ||
| declare const TYPE_REQUEST: "q"; | ||
| interface RpcRequest { | ||
| /** | ||
| * Type | ||
| */ | ||
| t: typeof TYPE_REQUEST; | ||
| /** | ||
| * ID | ||
| */ | ||
| i?: string; | ||
| /** | ||
| * Method | ||
| */ | ||
| m: string; | ||
| /** | ||
| * Arguments | ||
| */ | ||
| a: any[]; | ||
| /** | ||
| * Optional | ||
| */ | ||
| o?: boolean; | ||
| } | ||
| //#endregion | ||
| //#region src/utils.d.ts | ||
| type ArgumentsType<T> = T extends ((...args: infer A) => any) ? A : never; | ||
| type ReturnType<T> = T extends ((...args: any) => infer R) ? R : never; | ||
| type Thenable<T> = T | PromiseLike<T>; | ||
| //#endregion | ||
| //#region src/main.d.ts | ||
| type PromisifyFn<T> = ReturnType<T> extends Promise<any> ? T : (...args: ArgumentsType<T>) => Promise<Awaited<ReturnType<T>>>; | ||
| type BirpcResolver<This> = (this: This, name: string, resolved: (...args: unknown[]) => unknown) => Thenable<((...args: any[]) => any) | undefined>; | ||
| interface ChannelOptions { | ||
| /** | ||
| * Function to post raw message | ||
| */ | ||
| post: (data: any, ...extras: any[]) => Thenable<any>; | ||
| /** | ||
| * Listener to receive raw message | ||
| */ | ||
| on: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>; | ||
| /** | ||
| * Clear the listener when `$close` is called | ||
| */ | ||
| off?: (fn: (data: any, ...extras: any[]) => void) => Thenable<any>; | ||
| /** | ||
| * Custom function to serialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| serialize?: (data: any) => any; | ||
| /** | ||
| * Custom function to deserialize data | ||
| * | ||
| * by default it passes the data as-is | ||
| */ | ||
| deserialize?: (data: any) => any; | ||
| /** | ||
| * Call the methods with the RPC context or the original functions object | ||
| */ | ||
| bind?: 'rpc' | 'functions'; | ||
| /** | ||
| * Custom meta data to attached to the RPC instance's `$meta` property | ||
| */ | ||
| meta?: any; | ||
| } | ||
| interface EventOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> { | ||
| /** | ||
| * Names of remote functions that do not need response. | ||
| */ | ||
| eventNames?: (keyof RemoteFunctions)[]; | ||
| /** | ||
| * Maximum timeout for waiting for response, in milliseconds. | ||
| * | ||
| * @default 60_000 | ||
| */ | ||
| timeout?: number; | ||
| /** | ||
| * Whether to proxy the remote functions. | ||
| * | ||
| * When `proxify` is false, calling the remote function | ||
| * with `rpc.$call('method', ...args)` instead of `rpc.method(...args)` | ||
| * explicitly is required. | ||
| * | ||
| * @default true | ||
| */ | ||
| proxify?: Proxify; | ||
| /** | ||
| * Custom resolver to resolve function to be called | ||
| * | ||
| * For advanced use cases only | ||
| */ | ||
| resolver?: BirpcResolver<BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>>; | ||
| /** | ||
| * Hook triggered before an event is sent to the remote | ||
| * | ||
| * @param req - Request parameters | ||
| * @param next - Function to continue the request | ||
| * @param resolve - Function to resolve the response directly | ||
| */ | ||
| onRequest?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, req: RpcRequest, next: (req?: RpcRequest) => Promise<any>, resolve: (res: any) => void) => void | Promise<void>; | ||
| /** | ||
| * Custom error handler for errors occurred in local functions being called | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onFunctionError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName: string, args: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for errors occurred during serialization or messsaging | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onGeneralError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, error: Error, functionName?: string, args?: any[]) => boolean | void; | ||
| /** | ||
| * Custom error handler for timeouts | ||
| * | ||
| * @returns `true` to prevent the error from being thrown | ||
| */ | ||
| onTimeoutError?: (this: BirpcReturn<RemoteFunctions, LocalFunctions, Proxify>, functionName: string, args: any[]) => boolean | void; | ||
| } | ||
| type BirpcOptions<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = EventOptions<RemoteFunctions, LocalFunctions, Proxify> & ChannelOptions; | ||
| type BirpcFn<T> = PromisifyFn<T> & { | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| asEvent: (...args: ArgumentsType<T>) => Promise<void>; | ||
| }; | ||
| interface BirpcReturnBuiltin<RemoteFunctions, LocalFunctions = Record<string, unknown>> { | ||
| /** | ||
| * Raw functions object | ||
| */ | ||
| $functions: LocalFunctions; | ||
| /** | ||
| * Whether the RPC is closed | ||
| */ | ||
| readonly $closed: boolean; | ||
| /** | ||
| * Custom meta data attached to the RPC instance | ||
| */ | ||
| readonly $meta: any; | ||
| /** | ||
| * Close the RPC connection | ||
| */ | ||
| $close: (error?: Error) => void; | ||
| /** | ||
| * Reject pending calls | ||
| */ | ||
| $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[]; | ||
| /** | ||
| * Call the remote function and wait for the result. | ||
| * An alternative to directly calling the function | ||
| */ | ||
| $call: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]>>>; | ||
| /** | ||
| * Same as `$call`, but returns `undefined` if the function is not defined on the remote side. | ||
| */ | ||
| $callOptional: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<Awaited<ReturnType<RemoteFunctions[K$1]> | undefined>>; | ||
| /** | ||
| * Send event without asking for response | ||
| */ | ||
| $callEvent: <K$1 extends keyof RemoteFunctions>(method: K$1, ...args: ArgumentsType<RemoteFunctions[K$1]>) => Promise<void>; | ||
| /** | ||
| * Call the remote function with the raw options. | ||
| */ | ||
| $callRaw: (options: { | ||
| method: string; | ||
| args: unknown[]; | ||
| event?: boolean; | ||
| optional?: boolean; | ||
| }) => Promise<Awaited<ReturnType<any>>[]>; | ||
| } | ||
| type ProxifiedRemoteFunctions<RemoteFunctions extends object = Record<string, unknown>> = { [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]> }; | ||
| type BirpcReturn<RemoteFunctions extends object = Record<string, unknown>, LocalFunctions extends object = Record<string, unknown>, Proxify extends boolean = true> = Proxify extends true ? ProxifiedRemoteFunctions<RemoteFunctions> & BirpcReturnBuiltin<RemoteFunctions, LocalFunctions> : BirpcReturnBuiltin<RemoteFunctions, LocalFunctions>; | ||
| type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>; | ||
| interface PromiseEntry { | ||
| resolve: (arg: any) => void; | ||
| reject: (error: any) => void; | ||
| method: string; | ||
| timeoutId?: ReturnType<typeof setTimeout>; | ||
| } | ||
| declare const setTimeout: typeof globalThis.setTimeout; | ||
| type WorkerRPC = BirpcReturn<RuntimeRPC, RunnerRPC>; | ||
| interface ContextTestEnvironment { | ||
| name: string; | ||
| options: Record<string, any> | null; | ||
| } | ||
| interface WorkerTestEnvironment { | ||
| name: string; | ||
| options: Record<string, any> | null; | ||
| } | ||
| type TestExecutionMethod = "run" | "collect"; | ||
| interface WorkerExecuteContext { | ||
| files: FileSpecification[]; | ||
| providedContext: Record<string, any>; | ||
| invalidates?: string[]; | ||
| environment: ContextTestEnvironment; | ||
| /** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */ | ||
| workerId: number; | ||
| } | ||
| interface ContextRPC { | ||
| pool: string; | ||
| config: SerializedConfig; | ||
| projectName: string; | ||
| environment: WorkerTestEnvironment; | ||
| rpc: WorkerRPC; | ||
| files: FileSpecification[]; | ||
| providedContext: Record<string, any>; | ||
| invalidates?: string[]; | ||
| /** Exposed to test runner as `VITEST_WORKER_ID`. Value is unique per each isolated worker. */ | ||
| workerId: number; | ||
| concurrencyId: number; | ||
| } | ||
| interface WorkerSetupContext { | ||
| environment: WorkerTestEnvironment; | ||
| pool: string; | ||
| config: SerializedConfig; | ||
| projectName: string; | ||
| rpc: WorkerRPC; | ||
| } | ||
| interface WorkerGlobalState { | ||
| ctx: ContextRPC; | ||
| config: SerializedConfig; | ||
| rpc: WorkerRPC; | ||
| current?: Task; | ||
| filepath?: string; | ||
| metaEnv: { | ||
| [key: string]: any; | ||
| BASE_URL: string; | ||
| MODE: string; | ||
| DEV: boolean; | ||
| PROD: boolean; | ||
| SSR: boolean; | ||
| }; | ||
| environment: Environment; | ||
| evaluatedModules: EvaluatedModules; | ||
| resolvingModules: Set<string>; | ||
| moduleExecutionInfo: Map<string, any>; | ||
| getterTracker?: GetterTracker; | ||
| onCancel: (listener: (reason: CancelReason) => unknown) => void; | ||
| onCleanup: (listener: () => unknown) => void; | ||
| providedContext: Record<string, any>; | ||
| durations: { | ||
| environment: number; | ||
| prepare: number; | ||
| }; | ||
| onFilterStackTrace?: (trace: string) => string; | ||
| } | ||
| export type { BirpcReturn as B, ContextRPC as C, TestExecutionMethod as T, WorkerGlobalState as W, ContextTestEnvironment as a, WorkerExecuteContext as b, WorkerTestEnvironment as c, WorkerSetupContext as d, BirpcOptions as e }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Mixed license
LicensePackage contains multiple licenses.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Network access
Supply chain riskThis module accesses the network.
Found 4 instances
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 2 instances
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Mixed license
LicensePackage contains multiple licenses.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2598975
12.25%25
-16.67%104
9.47%68344
11.12%145
-3.97%14
-12.5%34
17.24%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated