vitest 0.30.1 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,14 @@
1
1
  import { resolve as resolve$2, relative, isAbsolute, dirname, basename, normalize, join, extname, toNamespacedPath } from 'pathe';
2
2
  import { E as EXIT_CODE_RESTART, c as configFiles, d as defaultPort, a as defaultBrowserPort, w as workspacesFiles, C as CONFIG_NAMES } from './vendor-constants.538d9b49.js';
3
- import { g as getCoverageProvider, C as CoverageProviderMap } from './vendor-coverage.a585b712.js';
3
+ import { g as getCoverageProvider, C as CoverageProviderMap } from './vendor-coverage.c8fd34c3.js';
4
4
  import { g as getEnvPackageName } from './vendor-index.75f2b63d.js';
5
+ import url, { fileURLToPath, pathToFileURL } from 'node:url';
5
6
  import c from 'picocolors';
6
7
  import { isPackageExists, resolveModule } from 'local-pkg';
7
8
  import { i as isNode, r as relativePath, a as removeUndefinedValues, b as isWindows } from './vendor-index.fad2598b.js';
8
9
  import { isCI } from 'std-env';
9
10
  import { loadConfigFromFile, createServer, mergeConfig } from 'vite';
10
11
  import path$a from 'node:path';
11
- import url, { fileURLToPath, pathToFileURL } from 'node:url';
12
12
  import process$1 from 'node:process';
13
13
  import fs$8, { promises, existsSync, readFileSync } from 'node:fs';
14
14
  import p from 'path';
@@ -21,6 +21,7 @@ import { c as commonjsGlobal } from './vendor-_commonjsHelpers.76cdd49e.js';
21
21
  import { slash as slash$2, normalizeRequestId, cleanUrl } from 'vite-node/utils';
22
22
  import { ViteNodeRunner } from 'vite-node/client';
23
23
  import { SnapshotManager } from '@vitest/snapshot/manager';
24
+ import { ViteNodeServer } from 'vite-node/server';
24
25
  import { d as distDir, r as rootDir } from './vendor-paths.84fc7a99.js';
25
26
  import v8 from 'node:v8';
26
27
  import { fork } from 'node:child_process';
@@ -28,7 +29,7 @@ import { g as groupBy, a as getEnvironmentTransformMode, c as createBirpc, A as
28
29
  import { MessageChannel } from 'node:worker_threads';
29
30
  import { cpus, hostname } from 'node:os';
30
31
  import Tinypool from 'tinypool';
31
- import { createDefer, getSafeTimers, notNullish, parseErrorStacktrace, shuffle, stringify as stringify$5, positionToOffset, lineSplitRE, getCallLastIndex } from '@vitest/utils';
32
+ import { createDefer, getSafeTimers, notNullish, parseErrorStacktrace, shuffle, stringify as stringify$5, positionToOffset, lineSplitRE } from '@vitest/utils';
32
33
  import { performance } from 'node:perf_hooks';
33
34
  import { g as getFullName, h as hasFailedSnapshot } from './vendor-tasks.042d6084.js';
34
35
  import { getTests, hasFailed, getSuites, generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks } from '@vitest/runner/utils';
@@ -36,13 +37,11 @@ import { createRequire } from 'node:module';
36
37
  import { createHash } from 'node:crypto';
37
38
  import { s as signalExit, e as execa } from './vendor-index.c1e09929.js';
38
39
  import { writeFile, rm } from 'node:fs/promises';
39
- import { SourceMapConsumer } from 'source-map';
40
40
  import cn from 'module';
41
41
  import { parse as parse$4 } from 'acorn';
42
- import { ancestor } from 'acorn-walk';
42
+ import { ancestor, simple, findNodeAround } from 'acorn-walk';
43
43
  import MagicString from 'magic-string';
44
44
  import { stripLiteral } from 'strip-literal';
45
- import { ViteNodeServer } from 'vite-node/server';
46
45
  import readline from 'node:readline';
47
46
  import require$$0$4 from 'readline';
48
47
 
@@ -61,10 +60,11 @@ function _mergeNamespaces(n, m) {
61
60
  return Object.freeze(n);
62
61
  }
63
62
 
64
- var version$1 = "0.30.1";
63
+ var version$1 = "0.31.0";
65
64
 
65
+ const __dirname$1 = url.fileURLToPath(new URL(".", import.meta.url));
66
66
  async function ensurePackageInstalled(dependency, root) {
67
- if (isPackageExists(dependency, { paths: [root] }))
67
+ if (isPackageExists(dependency, { paths: [root, __dirname$1] }))
68
68
  return true;
69
69
  const promptInstall = !isCI && process.stdout.isTTY;
70
70
  process.stderr.write(c.red(`${c.inverse(c.red(" MISSING DEP "))} Can not find dependency '${dependency}'
@@ -79,7 +79,7 @@ async function ensurePackageInstalled(dependency, root) {
79
79
  message: c.reset(`Do you want to install ${c.green(dependency)}?`)
80
80
  });
81
81
  if (install) {
82
- await (await import('./chunk-install-pkg.ee5cc9a8.js')).installPackage(dependency, { dev: true });
82
+ await (await import('./chunk-install-pkg.e0e70dba.js')).installPackage(dependency, { dev: true });
83
83
  process.stderr.write(c.yellow(`
84
84
  Package ${dependency} installed, re-run the command to start.
85
85
  `));
@@ -952,7 +952,7 @@ function splitToRanges(min, max) {
952
952
  }
953
953
 
954
954
  stops = [...stops];
955
- stops.sort(compare$1);
955
+ stops.sort(compare);
956
956
  return stops;
957
957
  }
958
958
 
@@ -1058,7 +1058,7 @@ function zip(a, b) {
1058
1058
  return arr;
1059
1059
  }
1060
1060
 
1061
- function compare$1(a, b) {
1061
+ function compare(a, b) {
1062
1062
  return a > b ? 1 : b > a ? -1 : 0;
1063
1063
  }
1064
1064
 
@@ -7055,15 +7055,22 @@ function createMethodsRPC(project) {
7055
7055
  },
7056
7056
  onFinished(files) {
7057
7057
  project.report("onFinished", files, ctx.state.getUnhandledErrors());
7058
+ },
7059
+ onCancel(reason) {
7060
+ ctx.cancelCurrentRun(reason);
7061
+ },
7062
+ getCountOfFailedTests() {
7063
+ return ctx.state.getCountOfFailedTests();
7058
7064
  }
7059
7065
  };
7060
7066
  }
7061
7067
 
7062
7068
  const childPath = fileURLToPath(pathToFileURL(resolve$2(distDir, "./child.js")).href);
7063
7069
  function setupChildProcessChannel(project, fork2) {
7064
- createBirpc(
7070
+ const rpc = createBirpc(
7065
7071
  createMethodsRPC(project),
7066
7072
  {
7073
+ eventNames: ["onCancel"],
7067
7074
  serialize: v8.serialize,
7068
7075
  deserialize: (v) => v8.deserialize(Buffer.from(v)),
7069
7076
  post(v) {
@@ -7074,6 +7081,7 @@ function setupChildProcessChannel(project, fork2) {
7074
7081
  }
7075
7082
  }
7076
7083
  );
7084
+ project.ctx.onCancel((reason) => rpc.onCancel(reason));
7077
7085
  }
7078
7086
  function stringifyRegex(input) {
7079
7087
  if (typeof input === "string")
@@ -7161,9 +7169,10 @@ function createWorkerChannel(project) {
7161
7169
  const channel = new MessageChannel();
7162
7170
  const port = channel.port2;
7163
7171
  const workerPort = channel.port1;
7164
- createBirpc(
7172
+ const rpc = createBirpc(
7165
7173
  createMethodsRPC(project),
7166
7174
  {
7175
+ eventNames: ["onCancel"],
7167
7176
  post(v) {
7168
7177
  port.postMessage(v);
7169
7178
  },
@@ -7172,6 +7181,7 @@ function createWorkerChannel(project) {
7172
7181
  }
7173
7182
  }
7174
7183
  );
7184
+ project.ctx.onCancel((reason) => rpc.onCancel(reason));
7175
7185
  return { workerPort, port };
7176
7186
  }
7177
7187
  function createThreadsPool(ctx, { execArgv, env }) {
@@ -7218,6 +7228,8 @@ function createThreadsPool(ctx, { execArgv, env }) {
7218
7228
  } catch (error) {
7219
7229
  if (error instanceof Error && /Failed to terminate worker/.test(error.message))
7220
7230
  ctx.state.addProcessTimeoutCause(`Failed to terminate worker while running ${files.join(", ")}.`);
7231
+ else if (ctx.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message))
7232
+ ctx.state.cancelFiles(files, ctx.config.root);
7221
7233
  else
7222
7234
  throw error;
7223
7235
  } finally {
@@ -7228,6 +7240,7 @@ function createThreadsPool(ctx, { execArgv, env }) {
7228
7240
  const Sequencer = ctx.config.sequence.sequencer;
7229
7241
  const sequencer = new Sequencer(ctx);
7230
7242
  return async (specs, invalidates) => {
7243
+ ctx.onCancel(() => pool.cancelPendingTasks());
7231
7244
  const configs = /* @__PURE__ */ new Map();
7232
7245
  const getConfig = (project) => {
7233
7246
  if (configs.has(project))
@@ -7295,6 +7308,11 @@ function createBrowserPool(ctx) {
7295
7308
  };
7296
7309
  const runTests = async (project, files) => {
7297
7310
  var _a;
7311
+ ctx.state.clearFiles(project, files);
7312
+ let isCancelled = false;
7313
+ project.ctx.onCancel(() => {
7314
+ isCancelled = true;
7315
+ });
7298
7316
  const provider = project.browserProvider;
7299
7317
  providers.add(provider);
7300
7318
  const origin = `http://${((_a = ctx.config.browser.api) == null ? void 0 : _a.host) || "localhost"}:${project.browser.config.server.port}`;
@@ -7302,6 +7320,10 @@ function createBrowserPool(ctx) {
7302
7320
  const isolate = project.config.isolate;
7303
7321
  if (isolate) {
7304
7322
  for (const path of paths) {
7323
+ if (isCancelled) {
7324
+ ctx.state.cancelFiles(files.slice(paths.indexOf(path)), ctx.config.root);
7325
+ break;
7326
+ }
7305
7327
  const url = new URL("/", origin);
7306
7328
  url.searchParams.append("path", path);
7307
7329
  url.searchParams.set("id", path);
@@ -7353,6 +7375,8 @@ function createPool(ctx) {
7353
7375
  }
7354
7376
  function getPoolName([project, file]) {
7355
7377
  for (const [glob, pool] of project.config.poolMatchGlobs || []) {
7378
+ if (pool === "browser")
7379
+ throw new Error('Since Vitest 0.31.0 "browser" pool is not supported in "poolMatchGlobs". You can create a workspace to run some of your tests in browser in parallel. Read more: https://vitest.dev/guide/workspace');
7356
7380
  if (micromatch_1.isMatch(file, glob, { cwd: project.config.root }))
7357
7381
  return pool;
7358
7382
  }
@@ -7612,6 +7636,8 @@ const WAIT_FOR_CHANGE_PASS = `
7612
7636
  ${c.bold(c.inverse(c.green(" PASS ")))}${c.green(" Waiting for file changes...")}`;
7613
7637
  const WAIT_FOR_CHANGE_FAIL = `
7614
7638
  ${c.bold(c.inverse(c.red(" FAIL ")))}${c.red(" Tests failed. Watching for file changes...")}`;
7639
+ const WAIT_FOR_CHANGE_CANCELLED = `
7640
+ ${c.bold(c.inverse(c.red(" CANCELLED ")))}${c.red(" Test run cancelled. Watching for file changes...")}`;
7615
7641
  const LAST_RUN_LOG_TIMEOUT = 1500;
7616
7642
  class BaseReporter {
7617
7643
  constructor() {
@@ -7689,8 +7715,11 @@ class BaseReporter {
7689
7715
  this.resetLastRunLog();
7690
7716
  const failed = errors.length > 0 || hasFailed(files);
7691
7717
  const failedSnap = hasFailedSnapshot(files);
7718
+ const cancelled = this.ctx.isCancelling;
7692
7719
  if (failed)
7693
7720
  this.ctx.logger.log(WAIT_FOR_CHANGE_FAIL);
7721
+ else if (cancelled)
7722
+ this.ctx.logger.log(WAIT_FOR_CHANGE_CANCELLED);
7694
7723
  else
7695
7724
  this.ctx.logger.log(WAIT_FOR_CHANGE_PASS);
7696
7725
  const hints = [];
@@ -8834,7 +8863,7 @@ function renderBenchmark$1(task, tasks) {
8834
8863
  ].join("");
8835
8864
  }
8836
8865
  function renderTree$1(tasks, options, level = 0, maxRows) {
8837
- var _a, _b, _c, _d, _e, _f, _g, _h;
8866
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
8838
8867
  const output = [];
8839
8868
  let currentRowCount = 0;
8840
8869
  for (const task of [...tasks].reverse()) {
@@ -8851,19 +8880,21 @@ function renderTree$1(tasks, options, level = 0, maxRows) {
8851
8880
  }
8852
8881
  if (task.mode === "skip" || task.mode === "todo")
8853
8882
  suffix += ` ${c.dim(c.gray("[skipped]"))}`;
8854
- if (((_c = task.result) == null ? void 0 : _c.duration) != null) {
8883
+ if (task.type === "test" && ((_c = task.result) == null ? void 0 : _c.repeatCount) && task.result.repeatCount > 1)
8884
+ suffix += c.yellow(` (repeat x${task.result.repeatCount})`);
8885
+ if (((_d = task.result) == null ? void 0 : _d.duration) != null) {
8855
8886
  if (task.result.duration > DURATION_LONG$1)
8856
8887
  suffix += c.yellow(` ${Math.round(task.result.duration)}${c.dim("ms")}`);
8857
8888
  }
8858
- if (options.showHeap && ((_d = task.result) == null ? void 0 : _d.heap) != null)
8889
+ if (options.showHeap && ((_e = task.result) == null ? void 0 : _e.heap) != null)
8859
8890
  suffix += c.magenta(` ${Math.floor(task.result.heap / 1024 / 1024)} MB heap used`);
8860
8891
  let name = task.name;
8861
8892
  if (level === 0)
8862
8893
  name = formatFilepath$1(name);
8863
8894
  const padding = " ".repeat(level);
8864
- const body = ((_e = task.meta) == null ? void 0 : _e.benchmark) ? renderBenchmark$1(task, tasks) : name;
8895
+ const body = ((_f = task.meta) == null ? void 0 : _f.benchmark) ? renderBenchmark$1(task, tasks) : name;
8865
8896
  taskOutput.push(padding + prefix + body + suffix);
8866
- if (((_f = task.result) == null ? void 0 : _f.state) !== "pass" && outputMap$1.get(task) != null) {
8897
+ if (((_g = task.result) == null ? void 0 : _g.state) !== "pass" && outputMap$1.get(task) != null) {
8867
8898
  let data = outputMap$1.get(task);
8868
8899
  if (typeof data === "string") {
8869
8900
  data = stripAnsi(data.trim().split("\n").filter(Boolean).pop());
@@ -8878,8 +8909,14 @@ function renderTree$1(tasks, options, level = 0, maxRows) {
8878
8909
  taskOutput.push(renderHookState(task, "beforeAll", level + 1));
8879
8910
  taskOutput.push(renderHookState(task, "beforeEach", level + 1));
8880
8911
  if (task.type === "suite" && task.tasks.length > 0) {
8881
- if (((_g = task.result) == null ? void 0 : _g.state) === "fail" || ((_h = task.result) == null ? void 0 : _h.state) === "run" || options.renderSucceed)
8882
- taskOutput.push(renderTree$1(task.tasks, options, level + 1, maxRows));
8912
+ if (((_h = task.result) == null ? void 0 : _h.state) === "fail" || ((_i = task.result) == null ? void 0 : _i.state) === "run" || options.renderSucceed) {
8913
+ if (options.logger.ctx.config.hideSkippedTests) {
8914
+ const filteredTasks = task.tasks.filter((t) => t.mode !== "skip" && t.mode !== "todo");
8915
+ taskOutput.push(renderTree$1(filteredTasks, options, level + 1, maxRows));
8916
+ } else {
8917
+ taskOutput.push(renderTree$1(task.tasks, options, level + 1, maxRows));
8918
+ }
8919
+ }
8883
8920
  }
8884
8921
  taskOutput.push(renderHookState(task, "afterAll", level + 1));
8885
8922
  taskOutput.push(renderHookState(task, "afterEach", level + 1));
@@ -8896,14 +8933,26 @@ function createListRenderer(_tasks, options) {
8896
8933
  let timer;
8897
8934
  const log = options.logger.logUpdate;
8898
8935
  function update() {
8899
- log(renderTree$1(
8900
- tasks,
8901
- options,
8902
- 0,
8903
- // log-update already limits the amount of printed rows to fit the current terminal
8904
- // but we can optimize performance by doing it ourselves
8905
- process.stdout.rows
8906
- ));
8936
+ if (options.logger.ctx.config.hideSkippedTests) {
8937
+ const filteredTasks = tasks.filter((t) => t.mode !== "skip" && t.mode !== "todo");
8938
+ log(renderTree$1(
8939
+ filteredTasks,
8940
+ options,
8941
+ 0,
8942
+ // log-update already limits the amount of printed rows to fit the current terminal
8943
+ // but we can optimize performance by doing it ourselves
8944
+ process.stdout.rows
8945
+ ));
8946
+ } else {
8947
+ log(renderTree$1(
8948
+ tasks,
8949
+ options,
8950
+ 0,
8951
+ // log-update already limits the amount of printed rows to fit the current terminal
8952
+ // but we can optimize performance by doing it ourselves
8953
+ process.stdout.rows
8954
+ ));
8955
+ }
8907
8956
  }
8908
8957
  return {
8909
8958
  start() {
@@ -8922,7 +8971,12 @@ function createListRenderer(_tasks, options) {
8922
8971
  timer = void 0;
8923
8972
  }
8924
8973
  log.clear();
8925
- options.logger.log(renderTree$1(tasks, options));
8974
+ if (options.logger.ctx.config.hideSkippedTests) {
8975
+ const filteredTasks = tasks.filter((t) => t.mode !== "skip" && t.mode !== "todo");
8976
+ options.logger.log(renderTree$1(filteredTasks, options));
8977
+ } else {
8978
+ options.logger.log(renderTree$1(tasks, options));
8979
+ }
8926
8980
  return this;
8927
8981
  },
8928
8982
  clear() {
@@ -10022,6 +10076,26 @@ class StateManager {
10022
10076
  task.logs.push(log);
10023
10077
  }
10024
10078
  }
10079
+ getCountOfFailedTests() {
10080
+ return Array.from(this.idMap.values()).filter((t) => {
10081
+ var _a;
10082
+ return ((_a = t.result) == null ? void 0 : _a.state) === "fail";
10083
+ }).length;
10084
+ }
10085
+ cancelFiles(files, root) {
10086
+ this.collectFiles(files.map((filepath) => ({
10087
+ filepath,
10088
+ name: relative(root, filepath),
10089
+ id: filepath,
10090
+ mode: "skip",
10091
+ type: "suite",
10092
+ result: {
10093
+ state: "skip"
10094
+ },
10095
+ // Cancelled files have not yet collected tests
10096
+ tasks: []
10097
+ })));
10098
+ }
10025
10099
  }
10026
10100
 
10027
10101
  const defaultInclude = ["**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"];
@@ -10094,6 +10168,7 @@ const config = {
10094
10168
  update: false,
10095
10169
  reporters: [],
10096
10170
  silent: false,
10171
+ hideSkippedTests: false,
10097
10172
  api: false,
10098
10173
  ui: false,
10099
10174
  uiBase: "/__vitest__/",
@@ -10331,7 +10406,7 @@ function resolveApiServerConfig(options) {
10331
10406
  return api;
10332
10407
  }
10333
10408
  function resolveConfig(mode, options, viteConfig) {
10334
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
10409
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
10335
10410
  if (options.dom) {
10336
10411
  if (((_a = viteConfig.test) == null ? void 0 : _a.environment) != null && viteConfig.test.environment !== "happy-dom") {
10337
10412
  console.warn(
@@ -10476,6 +10551,7 @@ function resolveConfig(mode, options, viteConfig) {
10476
10551
  resolved.browser ?? (resolved.browser = {});
10477
10552
  (_i = resolved.browser).enabled ?? (_i.enabled = false);
10478
10553
  (_j = resolved.browser).headless ?? (_j.headless = isCI);
10554
+ (_k = resolved.browser).slowHijackESM ?? (_k.slowHijackESM = true);
10479
10555
  resolved.browser.api = resolveApiServerConfig(resolved.browser) || {
10480
10556
  port: defaultBrowserPort
10481
10557
  };
@@ -11034,2372 +11110,1986 @@ createLogUpdate(process$1.stdout);
11034
11110
 
11035
11111
  createLogUpdate(process$1.stderr);
11036
11112
 
11037
- var version = "0.30.1";
11038
-
11039
- function L(n){return /^\\\\\?\\/.test(n)?n:n.replace(/\\/g,"/")}function S(n,s){for(;;){const t=p.posix.join(n,s);if(require$$0$3.existsSync(t))return t;const e=p.dirname(n);if(e===n)return;n=e;}}const W=/^\.{1,2}(\/.*)?$/,M=n=>L(W.test(n)?n:`./${n}`);function un(n,s=!1){const t=n.length;let e=0,i="",l=0,c=16,a=0,g=0,v=0,k=0,r=0;function F(o,f){let u=0,j=0;for(;u<o||!f;){let T=n.charCodeAt(e);if(T>=48&&T<=57)j=j*16+T-48;else if(T>=65&&T<=70)j=j*16+T-65+10;else if(T>=97&&T<=102)j=j*16+T-97+10;else break;e++,u++;}return u<o&&(j=-1),j}function U(o){e=o,i="",l=0,c=16,r=0;}function A(){let o=e;if(n.charCodeAt(e)===48)e++;else for(e++;e<n.length&&_(n.charCodeAt(e));)e++;if(e<n.length&&n.charCodeAt(e)===46)if(e++,e<n.length&&_(n.charCodeAt(e)))for(e++;e<n.length&&_(n.charCodeAt(e));)e++;else return r=3,n.substring(o,e);let f=e;if(e<n.length&&(n.charCodeAt(e)===69||n.charCodeAt(e)===101))if(e++,(e<n.length&&n.charCodeAt(e)===43||n.charCodeAt(e)===45)&&e++,e<n.length&&_(n.charCodeAt(e))){for(e++;e<n.length&&_(n.charCodeAt(e));)e++;f=e;}else r=3;return n.substring(o,f)}function b(){let o="",f=e;for(;;){if(e>=t){o+=n.substring(f,e),r=2;break}const u=n.charCodeAt(e);if(u===34){o+=n.substring(f,e),e++;break}if(u===92){if(o+=n.substring(f,e),e++,e>=t){r=2;break}switch(n.charCodeAt(e++)){case 34:o+='"';break;case 92:o+="\\";break;case 47:o+="/";break;case 98:o+="\b";break;case 102:o+="\f";break;case 110:o+=`
11040
- `;break;case 114:o+="\r";break;case 116:o+=" ";break;case 117:const T=F(4,!0);T>=0?o+=String.fromCharCode(T):r=4;break;default:r=5;}f=e;continue}if(u>=0&&u<=31)if(N(u)){o+=n.substring(f,e),r=2;break}else r=6;e++;}return o}function O(){if(i="",r=0,l=e,g=a,k=v,e>=t)return l=t,c=17;let o=n.charCodeAt(e);if(R(o)){do e++,i+=String.fromCharCode(o),o=n.charCodeAt(e);while(R(o));return c=15}if(N(o))return e++,i+=String.fromCharCode(o),o===13&&n.charCodeAt(e)===10&&(e++,i+=`
11041
- `),a++,v=e,c=14;switch(o){case 123:return e++,c=1;case 125:return e++,c=2;case 91:return e++,c=3;case 93:return e++,c=4;case 58:return e++,c=6;case 44:return e++,c=5;case 34:return e++,i=b(),c=10;case 47:const f=e-1;if(n.charCodeAt(e+1)===47){for(e+=2;e<t&&!N(n.charCodeAt(e));)e++;return i=n.substring(f,e),c=12}if(n.charCodeAt(e+1)===42){e+=2;const u=t-1;let j=!1;for(;e<u;){const T=n.charCodeAt(e);if(T===42&&n.charCodeAt(e+1)===47){e+=2,j=!0;break}e++,N(T)&&(T===13&&n.charCodeAt(e)===10&&e++,a++,v=e);}return j||(e++,r=1),i=n.substring(f,e),c=13}return i+=String.fromCharCode(o),e++,c=16;case 45:if(i+=String.fromCharCode(o),e++,e===t||!_(n.charCodeAt(e)))return c=16;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return i+=A(),c=11;default:for(;e<t&&E(o);)e++,o=n.charCodeAt(e);if(l!==e){switch(i=n.substring(l,e),i){case"true":return c=8;case"false":return c=9;case"null":return c=7}return c=16}return i+=String.fromCharCode(o),e++,c=16}}function E(o){if(R(o)||N(o))return !1;switch(o){case 125:case 93:case 123:case 91:case 34:case 58:case 44:case 47:return !1}return !0}function $(){let o;do o=O();while(o>=12&&o<=15);return o}return {setPosition:U,getPosition:()=>e,scan:s?$:O,getToken:()=>c,getTokenValue:()=>i,getTokenOffset:()=>l,getTokenLength:()=>e-l,getTokenStartLine:()=>g,getTokenStartCharacter:()=>l-k,getTokenError:()=>r}}function R(n){return n===32||n===9}function N(n){return n===10||n===13}function _(n){return n>=48&&n<=57}var P;(function(n){n[n.lineFeed=10]="lineFeed",n[n.carriageReturn=13]="carriageReturn",n[n.space=32]="space",n[n._0=48]="_0",n[n._1=49]="_1",n[n._2=50]="_2",n[n._3=51]="_3",n[n._4=52]="_4",n[n._5=53]="_5",n[n._6=54]="_6",n[n._7=55]="_7",n[n._8=56]="_8",n[n._9=57]="_9",n[n.a=97]="a",n[n.b=98]="b",n[n.c=99]="c",n[n.d=100]="d",n[n.e=101]="e",n[n.f=102]="f",n[n.g=103]="g",n[n.h=104]="h",n[n.i=105]="i",n[n.j=106]="j",n[n.k=107]="k",n[n.l=108]="l",n[n.m=109]="m",n[n.n=110]="n",n[n.o=111]="o",n[n.p=112]="p",n[n.q=113]="q",n[n.r=114]="r",n[n.s=115]="s",n[n.t=116]="t",n[n.u=117]="u",n[n.v=118]="v",n[n.w=119]="w",n[n.x=120]="x",n[n.y=121]="y",n[n.z=122]="z",n[n.A=65]="A",n[n.B=66]="B",n[n.C=67]="C",n[n.D=68]="D",n[n.E=69]="E",n[n.F=70]="F",n[n.G=71]="G",n[n.H=72]="H",n[n.I=73]="I",n[n.J=74]="J",n[n.K=75]="K",n[n.L=76]="L",n[n.M=77]="M",n[n.N=78]="N",n[n.O=79]="O",n[n.P=80]="P",n[n.Q=81]="Q",n[n.R=82]="R",n[n.S=83]="S",n[n.T=84]="T",n[n.U=85]="U",n[n.V=86]="V",n[n.W=87]="W",n[n.X=88]="X",n[n.Y=89]="Y",n[n.Z=90]="Z",n[n.asterisk=42]="asterisk",n[n.backslash=92]="backslash",n[n.closeBrace=125]="closeBrace",n[n.closeBracket=93]="closeBracket",n[n.colon=58]="colon",n[n.comma=44]="comma",n[n.dot=46]="dot",n[n.doubleQuote=34]="doubleQuote",n[n.minus=45]="minus",n[n.openBrace=123]="openBrace",n[n.openBracket=91]="openBracket",n[n.plus=43]="plus",n[n.slash=47]="slash",n[n.formFeed=12]="formFeed",n[n.tab=9]="tab";})(P||(P={}));var h;(function(n){n.DEFAULT={allowTrailingComma:!1};})(h||(h={}));function fn(n,s=[],t=h.DEFAULT){let e=null,i=[];const l=[];function c(g){Array.isArray(i)?i.push(g):e!==null&&(i[e]=g);}return rn(n,{onObjectBegin:()=>{const g={};c(g),l.push(i),i=g,e=null;},onObjectProperty:g=>{e=g;},onObjectEnd:()=>{i=l.pop();},onArrayBegin:()=>{const g=[];c(g),l.push(i),i=g,e=null;},onArrayEnd:()=>{i=l.pop();},onLiteralValue:c,onError:(g,v,k)=>{s.push({error:g,offset:v,length:k});}},t),i[0]}function rn(n,s,t=h.DEFAULT){const e=un(n,!1),i=[];function l(m){return m?()=>m(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter()):()=>!0}function c(m){return m?()=>m(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter(),()=>i.slice()):()=>!0}function a(m){return m?w=>m(w,e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter()):()=>!0}function g(m){return m?w=>m(w,e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter(),()=>i.slice()):()=>!0}const v=c(s.onObjectBegin),k=g(s.onObjectProperty),r=l(s.onObjectEnd),F=c(s.onArrayBegin),U=l(s.onArrayEnd),A=g(s.onLiteralValue),b=a(s.onSeparator),O=l(s.onComment),E=a(s.onError),$=t&&t.disallowComments,o=t&&t.allowTrailingComma;function f(){for(;;){const m=e.scan();switch(e.getTokenError()){case 4:u(14);break;case 5:u(15);break;case 3:u(13);break;case 1:$||u(11);break;case 2:u(12);break;case 6:u(16);break}switch(m){case 12:case 13:$?u(10):O();break;case 16:u(1);break;case 15:case 14:break;default:return m}}}function u(m,w=[],H=[]){if(E(m),w.length+H.length>0){let I=e.getToken();for(;I!==17;){if(w.indexOf(I)!==-1){f();break}else if(H.indexOf(I)!==-1)break;I=f();}}}function j(m){const w=e.getTokenValue();return m?A(w):(k(w),i.push(w)),f(),!0}function T(){switch(e.getToken()){case 11:const m=e.getTokenValue();let w=Number(m);isNaN(w)&&(u(2),w=0),A(w);break;case 7:A(null);break;case 8:A(!0);break;case 9:A(!1);break;default:return !1}return f(),!0}function sn(){return e.getToken()!==10?(u(3,[],[2,5]),!1):(j(!1),e.getToken()===6?(b(":"),f(),V()||u(4,[],[2,5])):u(5,[],[2,5]),i.pop(),!0)}function on(){v(),f();let m=!1;for(;e.getToken()!==2&&e.getToken()!==17;){if(e.getToken()===5){if(m||u(4,[],[]),b(","),f(),e.getToken()===2&&o)break}else m&&u(6,[],[]);sn()||u(4,[],[2,5]),m=!0;}return r(),e.getToken()!==2?u(7,[2],[]):f(),!0}function ln(){F(),f();let m=!0,w=!1;for(;e.getToken()!==4&&e.getToken()!==17;){if(e.getToken()===5){if(w||u(4,[],[]),b(","),f(),e.getToken()===4&&o)break}else w&&u(6,[],[]);m?(i.push(0),m=!1):i[i.length-1]++,V()||u(4,[],[4,5]),w=!0;}return U(),m||i.pop(),e.getToken()!==4?u(8,[4],[]):f(),!0}function V(){switch(e.getToken()){case 3:return ln();case 1:return on();case 10:return j(!0);default:return T()}}return f(),e.getToken()===17?t.allowEmptyContent?!0:(u(4,[],[]),!1):V()?(e.getToken()!==17&&u(9,[],[]),!0):(u(4,[],[]),!1)}var X;(function(n){n[n.None=0]="None",n[n.UnexpectedEndOfComment=1]="UnexpectedEndOfComment",n[n.UnexpectedEndOfString=2]="UnexpectedEndOfString",n[n.UnexpectedEndOfNumber=3]="UnexpectedEndOfNumber",n[n.InvalidUnicode=4]="InvalidUnicode",n[n.InvalidEscapeCharacter=5]="InvalidEscapeCharacter",n[n.InvalidCharacter=6]="InvalidCharacter";})(X||(X={}));var Y;(function(n){n[n.OpenBraceToken=1]="OpenBraceToken",n[n.CloseBraceToken=2]="CloseBraceToken",n[n.OpenBracketToken=3]="OpenBracketToken",n[n.CloseBracketToken=4]="CloseBracketToken",n[n.CommaToken=5]="CommaToken",n[n.ColonToken=6]="ColonToken",n[n.NullKeyword=7]="NullKeyword",n[n.TrueKeyword=8]="TrueKeyword",n[n.FalseKeyword=9]="FalseKeyword",n[n.StringLiteral=10]="StringLiteral",n[n.NumericLiteral=11]="NumericLiteral",n[n.LineCommentTrivia=12]="LineCommentTrivia",n[n.BlockCommentTrivia=13]="BlockCommentTrivia",n[n.LineBreakTrivia=14]="LineBreakTrivia",n[n.Trivia=15]="Trivia",n[n.Unknown=16]="Unknown",n[n.EOF=17]="EOF";})(Y||(Y={}));const pn=fn;var Z;(function(n){n[n.InvalidSymbol=1]="InvalidSymbol",n[n.InvalidNumberFormat=2]="InvalidNumberFormat",n[n.PropertyNameExpected=3]="PropertyNameExpected",n[n.ValueExpected=4]="ValueExpected",n[n.ColonExpected=5]="ColonExpected",n[n.CommaExpected=6]="CommaExpected",n[n.CloseBraceExpected=7]="CloseBraceExpected",n[n.CloseBracketExpected=8]="CloseBracketExpected",n[n.EndOfFileExpected=9]="EndOfFileExpected",n[n.InvalidCommentToken=10]="InvalidCommentToken",n[n.UnexpectedEndOfComment=11]="UnexpectedEndOfComment",n[n.UnexpectedEndOfString=12]="UnexpectedEndOfString",n[n.UnexpectedEndOfNumber=13]="UnexpectedEndOfNumber",n[n.InvalidUnicode=14]="InvalidUnicode",n[n.InvalidEscapeCharacter=15]="InvalidEscapeCharacter",n[n.InvalidCharacter=16]="InvalidCharacter";})(Z||(Z={}));const q=n=>pn(require$$0$3.readFileSync(n,"utf8")),{existsSync:D}=require$$0$3,gn=()=>{const{findPnpApi:n}=cn;return n&&n(process.cwd())};function d(n){const s=q(n);return p.join(n,"..",s&&"tsconfig"in s?s.tsconfig:"tsconfig.json")}function mn(n,s){let t=n;const e=n[0]===".";if(e||p.isAbsolute(n)){if(e&&(t===".."&&(t+="/tsconfig.json"),t=p.resolve(s,t)),D(t)&&require$$0$3.statSync(t).isFile()||!t.endsWith(".json")&&(t+=".json",D(t)))return t;throw new Error(`File '${n}' not found.`)}const i=gn();if(i){const{resolveRequest:c}=i,[a,g]=n.split("/"),v=a.startsWith("@")?`${a}/${g}`:a;try{if(v===n){const k=c(p.join(v,"package.json"),s);if(k){const r=d(k);if(D(r))return r}}else {let k;try{k=c(n,s,{extensions:[".json"]});}catch{k=c(p.join(n,"tsconfig.json"),s);}if(k)return k}}catch{}}let l=S(s,p.join("node_modules",t));if(l){if(require$$0$3.statSync(l).isDirectory()){const c=p.join(l,"package.json");if(D(c)?l=d(c):l=p.join(l,"tsconfig.json"),D(l))return l}else if(l.endsWith(".json"))return l}if(!t.endsWith(".json")&&(t+=".json",l=S(s,p.join("node_modules",t)),l))return l;throw new Error(`File '${n}' not found.`)}const an=(n,s)=>{var t;const e=mn(n,s),i=J(e);if(delete i.references,(t=i.compilerOptions)!=null&&t.baseUrl){const{compilerOptions:l}=i;l.baseUrl=p.relative(s,p.join(p.dirname(e),l.baseUrl))||"./";}return i.files&&(i.files=i.files.map(l=>p.relative(s,p.join(p.dirname(e),l)))),i.include&&(i.include=i.include.map(l=>p.relative(s,p.join(p.dirname(e),l)))),i},J=n=>{let s;try{s=require$$0$3.realpathSync(n);}catch{throw new Error(`Cannot resolve tsconfig at path: ${n}`)}const t=p.dirname(s);let e=q(s)||{};if(typeof e!="object")throw new SyntaxError(`Failed to parse tsconfig at: ${n}`);if(e.extends){const i=Array.isArray(e.extends)?e.extends:[e.extends];delete e.extends;for(const l of i.reverse()){const c=an(l,t),a={...c,...e,compilerOptions:{...c.compilerOptions,...e.compilerOptions}};c.watchOptions&&(a.watchOptions={...c.watchOptions,...e.watchOptions}),e=a;}}if(e.compilerOptions){const{compilerOptions:i}=e;i.baseUrl&&(i.baseUrl=M(i.baseUrl)),i.outDir&&(Array.isArray(e.exclude)||(e.exclude=[]),e.exclude.push(i.outDir),i.outDir=M(i.outDir));}else e.compilerOptions={};if(e.files&&(e.files=e.files.map(M)),e.include&&(e.include=e.include.map(L)),e.watchOptions){const{watchOptions:i}=e;i.excludeDirectories&&(i.excludeDirectories=i.excludeDirectories.map(l=>L(p.resolve(t,l))));}return e};function kn(n=process.cwd(),s="tsconfig.json"){const t=S(L(n),s);if(!t)return null;const e=J(t);return {path:t,config:e}}p.posix;process.platform==="win32";
11113
+ var version = "0.31.0";
11042
11114
 
11043
- const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
11044
- const newLineRegExp = /\r?\n/;
11045
- const errCodeRegExp = /error TS(?<errCode>\d+)/;
11046
- async function makeTscErrorInfo(errInfo) {
11047
- var _a;
11048
- const [errFilePathPos = "", ...errMsgRawArr] = errInfo.split(":");
11049
- if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0)
11050
- return ["unknown filepath", null];
11051
- const errMsgRaw = errMsgRawArr.join("").trim();
11052
- const [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
11053
- if (!errFilePath || !errPos)
11054
- return ["unknown filepath", null];
11055
- const [errLine, errCol] = errPos.split(",");
11056
- if (!errLine || !errCol)
11057
- return [errFilePath, null];
11058
- const execArr = errCodeRegExp.exec(errMsgRaw);
11059
- if (!execArr)
11060
- return [errFilePath, null];
11061
- const errCodeStr = ((_a = execArr.groups) == null ? void 0 : _a.errCode) ?? "";
11062
- if (!errCodeStr)
11063
- return [errFilePath, null];
11064
- const line = Number(errLine);
11065
- const col = Number(errCol);
11066
- const errCode = Number(errCodeStr);
11067
- return [
11068
- errFilePath,
11069
- {
11070
- filePath: errFilePath,
11071
- errCode,
11072
- line,
11073
- column: col,
11074
- errMsg: errMsgRaw.slice(`error TS${errCode} `.length)
11075
- }
11076
- ];
11115
+ const comma = ','.charCodeAt(0);
11116
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
11117
+ const intToChar = new Uint8Array(64); // 64 possible chars.
11118
+ const charToInt = new Uint8Array(128); // z is 122 in ASCII
11119
+ for (let i = 0; i < chars.length; i++) {
11120
+ const c = chars.charCodeAt(i);
11121
+ intToChar[i] = c;
11122
+ charToInt[c] = i;
11077
11123
  }
11078
- async function getTsconfig(root, config) {
11079
- var _a;
11080
- const configName = ((_a = config.tsconfig) == null ? void 0 : _a.includes("jsconfig.json")) ? "jsconfig.json" : void 0;
11081
- const tsconfig = kn(config.tsconfig || root, configName);
11082
- if (!tsconfig)
11083
- throw new Error("no tsconfig.json found");
11084
- const tempConfigPath = join(dirname(tsconfig.path), "tsconfig.vitest-temp.json");
11085
- try {
11086
- const tmpTsConfig = { ...tsconfig.config };
11087
- tmpTsConfig.compilerOptions = tmpTsConfig.compilerOptions || {};
11088
- tmpTsConfig.compilerOptions.emitDeclarationOnly = false;
11089
- tmpTsConfig.compilerOptions.incremental = true;
11090
- tmpTsConfig.compilerOptions.tsBuildInfoFile = join(
11091
- __dirname,
11092
- "tsconfig.tmp.tsbuildinfo"
11093
- );
11094
- const tsconfigFinalContent = JSON.stringify(tmpTsConfig, null, 2);
11095
- await writeFile(tempConfigPath, tsconfigFinalContent);
11096
- return { path: tempConfigPath, config: tmpTsConfig };
11097
- } catch (err) {
11098
- throw new Error("failed to write tsconfig.temp.json", { cause: err });
11099
- }
11124
+ function decode(mappings) {
11125
+ const state = new Int32Array(5);
11126
+ const decoded = [];
11127
+ let index = 0;
11128
+ do {
11129
+ const semi = indexOf(mappings, index);
11130
+ const line = [];
11131
+ let sorted = true;
11132
+ let lastCol = 0;
11133
+ state[0] = 0;
11134
+ for (let i = index; i < semi; i++) {
11135
+ let seg;
11136
+ i = decodeInteger(mappings, i, state, 0); // genColumn
11137
+ const col = state[0];
11138
+ if (col < lastCol)
11139
+ sorted = false;
11140
+ lastCol = col;
11141
+ if (hasMoreVlq(mappings, i, semi)) {
11142
+ i = decodeInteger(mappings, i, state, 1); // sourcesIndex
11143
+ i = decodeInteger(mappings, i, state, 2); // sourceLine
11144
+ i = decodeInteger(mappings, i, state, 3); // sourceColumn
11145
+ if (hasMoreVlq(mappings, i, semi)) {
11146
+ i = decodeInteger(mappings, i, state, 4); // namesIndex
11147
+ seg = [col, state[1], state[2], state[3], state[4]];
11148
+ }
11149
+ else {
11150
+ seg = [col, state[1], state[2], state[3]];
11151
+ }
11152
+ }
11153
+ else {
11154
+ seg = [col];
11155
+ }
11156
+ line.push(seg);
11157
+ }
11158
+ if (!sorted)
11159
+ sort(line);
11160
+ decoded.push(line);
11161
+ index = semi + 1;
11162
+ } while (index <= mappings.length);
11163
+ return decoded;
11100
11164
  }
11101
- async function getRawErrsMapFromTsCompile(tscErrorStdout) {
11102
- const rawErrsMap = /* @__PURE__ */ new Map();
11103
- const infos = await Promise.all(
11104
- tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
11105
- if (!next)
11106
- return prev;
11107
- else if (!next.startsWith(" "))
11108
- prev.push(next);
11109
- else
11110
- prev[prev.length - 1] += `
11111
- ${next}`;
11112
- return prev;
11113
- }, []).map((errInfoLine) => makeTscErrorInfo(errInfoLine))
11114
- );
11115
- infos.forEach(([errFilePath, errInfo]) => {
11116
- var _a;
11117
- if (!errInfo)
11118
- return;
11119
- if (!rawErrsMap.has(errFilePath))
11120
- rawErrsMap.set(errFilePath, [errInfo]);
11121
- else
11122
- (_a = rawErrsMap.get(errFilePath)) == null ? void 0 : _a.push(errInfo);
11123
- });
11124
- return rawErrsMap;
11165
+ function indexOf(mappings, index) {
11166
+ const idx = mappings.indexOf(';', index);
11167
+ return idx === -1 ? mappings.length : idx;
11125
11168
  }
11126
-
11127
- function createIndexMap(source) {
11128
- const map = /* @__PURE__ */ new Map();
11129
- let index = 0;
11130
- let line = 1;
11131
- let column = 1;
11132
- for (const char of source) {
11133
- map.set(`${line}:${column}`, index++);
11134
- if (char === "\n" || char === "\r\n") {
11135
- line++;
11136
- column = 0;
11137
- } else {
11138
- column++;
11169
+ function decodeInteger(mappings, pos, state, j) {
11170
+ let value = 0;
11171
+ let shift = 0;
11172
+ let integer = 0;
11173
+ do {
11174
+ const c = mappings.charCodeAt(pos++);
11175
+ integer = charToInt[c];
11176
+ value |= (integer & 31) << shift;
11177
+ shift += 5;
11178
+ } while (integer & 32);
11179
+ const shouldNegate = value & 1;
11180
+ value >>>= 1;
11181
+ if (shouldNegate) {
11182
+ value = -0x80000000 | -value;
11139
11183
  }
11140
- }
11141
- return map;
11184
+ state[j] += value;
11185
+ return pos;
11186
+ }
11187
+ function hasMoreVlq(mappings, i, length) {
11188
+ if (i >= length)
11189
+ return false;
11190
+ return mappings.charCodeAt(i) !== comma;
11191
+ }
11192
+ function sort(line) {
11193
+ line.sort(sortComparator$1);
11194
+ }
11195
+ function sortComparator$1(a, b) {
11196
+ return a[0] - b[0];
11142
11197
  }
11143
11198
 
11144
- async function collectTests(ctx, filepath) {
11145
- const request = await ctx.vitenode.transformRequest(filepath, filepath);
11146
- if (!request)
11147
- return null;
11148
- const ast = parse$4(request.code, {
11149
- ecmaVersion: "latest",
11150
- allowAwaitOutsideFunction: true
11151
- });
11152
- const testFilepath = relative(ctx.config.root, filepath);
11153
- const file = {
11154
- filepath,
11155
- type: "suite",
11156
- id: generateHash(`${testFilepath}${ctx.config.name || ""}`),
11157
- name: testFilepath,
11158
- mode: "run",
11159
- tasks: [],
11160
- start: ast.start,
11161
- end: ast.end,
11162
- meta: { typecheck: true }
11163
- };
11164
- const definitions = [];
11165
- const getName = (callee) => {
11166
- var _a, _b, _c;
11167
- if (!callee)
11168
- return null;
11169
- if (callee.type === "Identifier")
11170
- return callee.name;
11171
- if (callee.type === "MemberExpression") {
11172
- if ((_b = (_a = callee.object) == null ? void 0 : _a.name) == null ? void 0 : _b.startsWith("__vite_ssr_"))
11173
- return getName(callee.property);
11174
- return getName((_c = callee.object) == null ? void 0 : _c.property);
11175
- }
11176
- return null;
11177
- };
11178
- ancestor(ast, {
11179
- CallExpression(node) {
11180
- var _a;
11181
- const { callee } = node;
11182
- const name = getName(callee);
11183
- if (!name)
11184
- return;
11185
- if (!["it", "test", "describe", "suite"].includes(name))
11186
- return;
11187
- const { arguments: [{ value: message }] } = node;
11188
- const property = (_a = callee == null ? void 0 : callee.property) == null ? void 0 : _a.name;
11189
- let mode = !property || property === name ? "run" : property;
11190
- if (!["run", "skip", "todo", "only", "skipIf", "runIf"].includes(mode))
11191
- throw new Error(`${name}.${mode} syntax is not supported when testing types`);
11192
- if (mode === "skipIf" || mode === "runIf")
11193
- mode = "skip";
11194
- definitions.push({
11195
- start: node.start,
11196
- end: node.end,
11197
- name: message,
11198
- type: name === "it" || name === "test" ? "test" : "suite",
11199
- mode
11200
- });
11199
+ // Matches the scheme of a URL, eg "http://"
11200
+ const schemeRegex = /^[\w+.-]+:\/\//;
11201
+ /**
11202
+ * Matches the parts of a URL:
11203
+ * 1. Scheme, including ":", guaranteed.
11204
+ * 2. User/password, including "@", optional.
11205
+ * 3. Host, guaranteed.
11206
+ * 4. Port, including ":", optional.
11207
+ * 5. Path, including "/", optional.
11208
+ * 6. Query, including "?", optional.
11209
+ * 7. Hash, including "#", optional.
11210
+ */
11211
+ const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
11212
+ /**
11213
+ * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
11214
+ * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
11215
+ *
11216
+ * 1. Host, optional.
11217
+ * 2. Path, which may include "/", guaranteed.
11218
+ * 3. Query, including "?", optional.
11219
+ * 4. Hash, including "#", optional.
11220
+ */
11221
+ const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
11222
+ var UrlType;
11223
+ (function (UrlType) {
11224
+ UrlType[UrlType["Empty"] = 1] = "Empty";
11225
+ UrlType[UrlType["Hash"] = 2] = "Hash";
11226
+ UrlType[UrlType["Query"] = 3] = "Query";
11227
+ UrlType[UrlType["RelativePath"] = 4] = "RelativePath";
11228
+ UrlType[UrlType["AbsolutePath"] = 5] = "AbsolutePath";
11229
+ UrlType[UrlType["SchemeRelative"] = 6] = "SchemeRelative";
11230
+ UrlType[UrlType["Absolute"] = 7] = "Absolute";
11231
+ })(UrlType || (UrlType = {}));
11232
+ function isAbsoluteUrl(input) {
11233
+ return schemeRegex.test(input);
11234
+ }
11235
+ function isSchemeRelativeUrl(input) {
11236
+ return input.startsWith('//');
11237
+ }
11238
+ function isAbsolutePath(input) {
11239
+ return input.startsWith('/');
11240
+ }
11241
+ function isFileUrl(input) {
11242
+ return input.startsWith('file:');
11243
+ }
11244
+ function isRelative(input) {
11245
+ return /^[.?#]/.test(input);
11246
+ }
11247
+ function parseAbsoluteUrl(input) {
11248
+ const match = urlRegex.exec(input);
11249
+ return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
11250
+ }
11251
+ function parseFileUrl(input) {
11252
+ const match = fileRegex.exec(input);
11253
+ const path = match[2];
11254
+ return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
11255
+ }
11256
+ function makeUrl(scheme, user, host, port, path, query, hash) {
11257
+ return {
11258
+ scheme,
11259
+ user,
11260
+ host,
11261
+ port,
11262
+ path,
11263
+ query,
11264
+ hash,
11265
+ type: UrlType.Absolute,
11266
+ };
11267
+ }
11268
+ function parseUrl(input) {
11269
+ if (isSchemeRelativeUrl(input)) {
11270
+ const url = parseAbsoluteUrl('http:' + input);
11271
+ url.scheme = '';
11272
+ url.type = UrlType.SchemeRelative;
11273
+ return url;
11201
11274
  }
11202
- });
11203
- let lastSuite = file;
11204
- const updateLatestSuite = (index) => {
11205
- const suite = lastSuite;
11206
- while (lastSuite !== file && lastSuite.end < index)
11207
- lastSuite = suite.suite;
11208
- return lastSuite;
11209
- };
11210
- definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
11211
- const latestSuite = updateLatestSuite(definition.start);
11212
- let mode = definition.mode;
11213
- if (latestSuite.mode !== "run")
11214
- mode = latestSuite.mode;
11215
- if (definition.type === "suite") {
11216
- const task2 = {
11217
- type: definition.type,
11218
- id: "",
11219
- suite: latestSuite,
11220
- file,
11221
- tasks: [],
11222
- mode,
11223
- name: definition.name,
11224
- end: definition.end,
11225
- start: definition.start,
11226
- meta: {
11227
- typecheck: true
11228
- }
11229
- };
11230
- definition.task = task2;
11231
- latestSuite.tasks.push(task2);
11232
- lastSuite = task2;
11233
- return;
11275
+ if (isAbsolutePath(input)) {
11276
+ const url = parseAbsoluteUrl('http://foo.com' + input);
11277
+ url.scheme = '';
11278
+ url.host = '';
11279
+ url.type = UrlType.AbsolutePath;
11280
+ return url;
11234
11281
  }
11235
- const task = {
11236
- type: definition.type,
11237
- id: "",
11238
- suite: latestSuite,
11239
- file,
11240
- mode,
11241
- context: {},
11242
- // not used in typecheck
11243
- name: definition.name,
11244
- end: definition.end,
11245
- start: definition.start,
11246
- meta: {
11247
- typecheck: true
11248
- }
11249
- };
11250
- definition.task = task;
11251
- latestSuite.tasks.push(task);
11252
- });
11253
- calculateSuiteHash(file);
11254
- const hasOnly = someTasksAreOnly(file);
11255
- interpretTaskModes(file, ctx.config.testNamePattern, hasOnly, false, ctx.config.allowOnly);
11256
- return {
11257
- file,
11258
- parsed: request.code,
11259
- filepath,
11260
- map: request.map,
11261
- definitions
11262
- };
11282
+ if (isFileUrl(input))
11283
+ return parseFileUrl(input);
11284
+ if (isAbsoluteUrl(input))
11285
+ return parseAbsoluteUrl(input);
11286
+ const url = parseAbsoluteUrl('http://foo.com/' + input);
11287
+ url.scheme = '';
11288
+ url.host = '';
11289
+ url.type = input
11290
+ ? input.startsWith('?')
11291
+ ? UrlType.Query
11292
+ : input.startsWith('#')
11293
+ ? UrlType.Hash
11294
+ : UrlType.RelativePath
11295
+ : UrlType.Empty;
11296
+ return url;
11263
11297
  }
11264
-
11265
- class TypeCheckError extends Error {
11266
- constructor(message, stacks) {
11267
- super(message);
11268
- this.message = message;
11269
- this.stacks = stacks;
11270
- this.name = "TypeCheckError";
11271
- }
11298
+ function stripPathFilename(path) {
11299
+ // If a path ends with a parent directory "..", then it's a relative path with excess parent
11300
+ // paths. It's not a file, so we can't strip it.
11301
+ if (path.endsWith('/..'))
11302
+ return path;
11303
+ const index = path.lastIndexOf('/');
11304
+ return path.slice(0, index + 1);
11272
11305
  }
11273
- class Typechecker {
11274
- constructor(ctx, files) {
11275
- this.ctx = ctx;
11276
- this.files = files;
11277
- this._result = {
11278
- files: [],
11279
- sourceErrors: []
11280
- };
11281
- this._tests = {};
11282
- }
11283
- onParseStart(fn) {
11284
- this._onParseStart = fn;
11285
- }
11286
- onParseEnd(fn) {
11287
- this._onParseEnd = fn;
11288
- }
11289
- onWatcherRerun(fn) {
11290
- this._onWatcherRerun = fn;
11291
- }
11292
- async collectFileTests(filepath) {
11293
- return collectTests(this.ctx, filepath);
11294
- }
11295
- getFiles() {
11296
- return this.files.filter((filename) => {
11297
- const extension = extname(filename);
11298
- return extension !== ".js" || this.allowJs;
11299
- });
11300
- }
11301
- async collectTests() {
11302
- const tests = (await Promise.all(
11303
- this.getFiles().map((filepath) => this.collectFileTests(filepath))
11304
- )).reduce((acc, data) => {
11305
- if (!data)
11306
- return acc;
11307
- acc[data.filepath] = data;
11308
- return acc;
11309
- }, {});
11310
- this._tests = tests;
11311
- return tests;
11312
- }
11313
- markPassed(file) {
11314
- var _a;
11315
- if (!((_a = file.result) == null ? void 0 : _a.state)) {
11316
- file.result = {
11317
- state: "pass"
11318
- };
11306
+ function mergePaths(url, base) {
11307
+ normalizePath(base, base.type);
11308
+ // If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
11309
+ // path).
11310
+ if (url.path === '/') {
11311
+ url.path = base.path;
11312
+ }
11313
+ else {
11314
+ // Resolution happens relative to the base path's directory, not the file.
11315
+ url.path = stripPathFilename(base.path) + url.path;
11319
11316
  }
11320
- const markTasks = (tasks) => {
11321
- var _a2;
11322
- for (const task of tasks) {
11323
- if ("tasks" in task)
11324
- markTasks(task.tasks);
11325
- if (!((_a2 = task.result) == null ? void 0 : _a2.state) && task.mode === "run") {
11326
- task.result = {
11327
- state: "pass"
11328
- };
11329
- }
11330
- }
11331
- };
11332
- markTasks(file.tasks);
11333
- }
11334
- async prepareResults(output) {
11335
- const typeErrors = await this.parseTscLikeOutput(output);
11336
- const testFiles = new Set(this.getFiles());
11337
- if (!this._tests)
11338
- this._tests = await this.collectTests();
11339
- const sourceErrors = [];
11340
- const files = [];
11341
- testFiles.forEach((path) => {
11342
- const { file, definitions, map, parsed } = this._tests[path];
11343
- const errors = typeErrors.get(path);
11344
- files.push(file);
11345
- if (!errors) {
11346
- this.markPassed(file);
11347
- return;
11348
- }
11349
- const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)];
11350
- const mapConsumer = map && new SourceMapConsumer(map);
11351
- const indexMap = createIndexMap(parsed);
11352
- const markState = (task, state) => {
11353
- task.result = {
11354
- state: task.mode === "run" || task.mode === "only" ? state : task.mode
11355
- };
11356
- if (task.suite)
11357
- markState(task.suite, state);
11358
- };
11359
- errors.forEach(({ error, originalError }) => {
11360
- var _a;
11361
- const processedPos = (mapConsumer == null ? void 0 : mapConsumer.generatedPositionFor({
11362
- line: originalError.line,
11363
- column: originalError.column,
11364
- source: basename(path)
11365
- })) || originalError;
11366
- const line = processedPos.line ?? originalError.line;
11367
- const column = processedPos.column ?? originalError.column;
11368
- const index = indexMap.get(`${line}:${column}`);
11369
- const definition = index != null && sortedDefinitions.find((def) => def.start <= index && def.end >= index);
11370
- const suite = definition ? definition.task : file;
11371
- const state = suite.mode === "run" || suite.mode === "only" ? "fail" : suite.mode;
11372
- const errors2 = ((_a = suite.result) == null ? void 0 : _a.errors) || [];
11373
- suite.result = {
11374
- state,
11375
- errors: errors2
11376
- };
11377
- errors2.push(error);
11378
- if (state === "fail" && suite.suite)
11379
- markState(suite.suite, "fail");
11380
- });
11381
- this.markPassed(file);
11382
- });
11383
- typeErrors.forEach((errors, path) => {
11384
- if (!testFiles.has(path))
11385
- sourceErrors.push(...errors.map(({ error }) => error));
11386
- });
11387
- return {
11388
- files,
11389
- sourceErrors
11390
- };
11391
- }
11392
- async parseTscLikeOutput(output) {
11393
- const errorsMap = await getRawErrsMapFromTsCompile(output);
11394
- const typesErrors = /* @__PURE__ */ new Map();
11395
- errorsMap.forEach((errors, path) => {
11396
- const filepath = resolve$2(this.ctx.config.root, path);
11397
- const suiteErrors = errors.map((info) => {
11398
- const limit = Error.stackTraceLimit;
11399
- Error.stackTraceLimit = 0;
11400
- const error = new TypeCheckError(info.errMsg, [
11401
- {
11402
- file: filepath,
11403
- line: info.line,
11404
- column: info.column,
11405
- method: ""
11406
- }
11407
- ]);
11408
- Error.stackTraceLimit = limit;
11409
- return {
11410
- originalError: info,
11411
- error
11412
- };
11413
- });
11414
- typesErrors.set(filepath, suiteErrors);
11415
- });
11416
- return typesErrors;
11417
- }
11418
- async clear() {
11419
- if (this.tempConfigPath)
11420
- await rm(this.tempConfigPath, { force: true });
11421
- }
11422
- async stop() {
11423
- var _a;
11424
- await this.clear();
11425
- (_a = this.process) == null ? void 0 : _a.kill();
11426
- }
11427
- async ensurePackageInstalled(root, checker) {
11428
- if (checker !== "tsc" && checker !== "vue-tsc")
11429
- return;
11430
- const packageName = checker === "tsc" ? "typescript" : "vue-tsc";
11431
- await ensurePackageInstalled(packageName, root);
11432
- }
11433
- async prepare() {
11434
- const { root, typecheck } = this.ctx.config;
11435
- await this.ensurePackageInstalled(root, typecheck.checker);
11436
- const { config, path } = await getTsconfig(root, typecheck);
11437
- this.tempConfigPath = path;
11438
- this.allowJs = typecheck.allowJs || config.allowJs || false;
11439
- }
11440
- async start() {
11441
- var _a, _b, _c;
11442
- if (!this.tempConfigPath)
11443
- throw new Error("tsconfig was not initialized");
11444
- const { root, watch, typecheck } = this.ctx.config;
11445
- const args = ["--noEmit", "--pretty", "false", "-p", this.tempConfigPath];
11446
- if (watch)
11447
- args.push("--watch");
11448
- if (typecheck.allowJs)
11449
- args.push("--allowJs", "--checkJs");
11450
- let output = "";
11451
- const child = execa(typecheck.checker, args, {
11452
- cwd: root,
11453
- stdout: "pipe",
11454
- reject: false
11455
- });
11456
- this.process = child;
11457
- await ((_a = this._onParseStart) == null ? void 0 : _a.call(this));
11458
- let rerunTriggered = false;
11459
- (_b = child.stdout) == null ? void 0 : _b.on("data", (chunk) => {
11460
- var _a2;
11461
- output += chunk;
11462
- if (!watch)
11463
- return;
11464
- if (output.includes("File change detected") && !rerunTriggered) {
11465
- (_a2 = this._onWatcherRerun) == null ? void 0 : _a2.call(this);
11466
- this._result.sourceErrors = [];
11467
- this._result.files = [];
11468
- this._tests = null;
11469
- rerunTriggered = true;
11470
- }
11471
- if (/Found \w+ errors*. Watching for/.test(output)) {
11472
- rerunTriggered = false;
11473
- this.prepareResults(output).then((result) => {
11474
- var _a3;
11475
- this._result = result;
11476
- (_a3 = this._onParseEnd) == null ? void 0 : _a3.call(this, result);
11477
- });
11478
- output = "";
11479
- }
11480
- });
11481
- if (!watch) {
11482
- await child;
11483
- this._result = await this.prepareResults(output);
11484
- await ((_c = this._onParseEnd) == null ? void 0 : _c.call(this, this._result));
11485
- }
11486
- }
11487
- getResult() {
11488
- return this._result;
11489
- }
11490
- getTestFiles() {
11491
- return Object.values(this._tests || {}).map((i) => i.file);
11492
- }
11493
- getTestPacks() {
11494
- return Object.values(this._tests || {}).map(({ file }) => getTasks(file)).flat().map((i) => [i.id, void 0]);
11495
- }
11496
- }
11497
-
11498
- async function printError(error, ctx, options = {}) {
11499
- const { showCodeFrame = true, fullStack = false, type } = options;
11500
- let e = error;
11501
- if (isPrimitive(e)) {
11502
- e = {
11503
- message: String(error).split(/\n/g)[0],
11504
- stack: String(error)
11505
- };
11506
- }
11507
- if (!e) {
11508
- const error2 = new Error("unknown error");
11509
- e = {
11510
- message: e ?? error2.message,
11511
- stack: error2.stack
11512
- };
11513
- }
11514
- if (!ctx.config)
11515
- return printErrorMessage(e, ctx.logger);
11516
- const stacks = parseErrorStacktrace(e, fullStack ? [] : void 0);
11517
- const nearest = error instanceof TypeCheckError ? error.stacks[0] : stacks.find(
11518
- (stack) => ctx.getModuleProjects(stack.file).length && existsSync(stack.file)
11519
- );
11520
- const errorProperties = getErrorProperties(e);
11521
- if (type)
11522
- printErrorType(type, ctx);
11523
- printErrorMessage(e, ctx.logger);
11524
- if (e.frame) {
11525
- ctx.logger.error(c.yellow(e.frame));
11526
- } else {
11527
- printStack(ctx, stacks, nearest, errorProperties, (s) => {
11528
- if (showCodeFrame && s === nearest && nearest) {
11529
- const sourceCode = readFileSync(nearest.file, "utf-8");
11530
- ctx.logger.error(c.yellow(generateCodeFrame(sourceCode, 4, s.line, s.column)));
11531
- }
11532
- });
11533
- }
11534
- const testPath = e.VITEST_TEST_PATH;
11535
- const testName = e.VITEST_TEST_NAME;
11536
- const afterEnvTeardown = e.VITEST_AFTER_ENV_TEARDOWN;
11537
- if (testPath)
11538
- ctx.logger.error(c.red(`This error originated in "${c.bold(testPath)}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`));
11539
- if (testName) {
11540
- ctx.logger.error(c.red(`The latest test that might've caused the error is "${c.bold(testName)}". It might mean one of the following:
11541
- - The error was thrown, while Vitest was running this test.
11542
- - This was the last recorded test before the error was thrown, if error originated after test finished its execution.`));
11543
- }
11544
- if (afterEnvTeardown) {
11545
- ctx.logger.error(c.red("This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes:\n- cancel timeouts using clearTimeout and clearInterval\n- wait for promises to resolve using the await keyword"));
11546
- }
11547
- if (typeof e.cause === "object" && e.cause && "name" in e.cause) {
11548
- e.cause.name = `Caused by: ${e.cause.name}`;
11549
- await printError(e.cause, ctx, { fullStack, showCodeFrame: false });
11550
- }
11551
- handleImportOutsideModuleError(e.stack || e.stackStr || "", ctx);
11552
- if (e.diff)
11553
- displayDiff(e.diff, ctx.logger.console);
11554
- }
11555
- function printErrorType(type, ctx) {
11556
- ctx.logger.error(`
11557
- ${c.red(divider(c.bold(c.inverse(` ${type} `))))}`);
11558
- }
11559
- const skipErrorProperties = /* @__PURE__ */ new Set([
11560
- "nameStr",
11561
- "stack",
11562
- "cause",
11563
- "stacks",
11564
- "stackStr",
11565
- "type",
11566
- "showDiff",
11567
- "diff",
11568
- "actual",
11569
- "expected",
11570
- "VITEST_TEST_NAME",
11571
- "VITEST_TEST_PATH",
11572
- "VITEST_AFTER_ENV_TEARDOWN",
11573
- ...Object.getOwnPropertyNames(Error.prototype),
11574
- ...Object.getOwnPropertyNames(Object.prototype)
11575
- ]);
11576
- function getErrorProperties(e) {
11577
- const errorObject = /* @__PURE__ */ Object.create(null);
11578
- if (e.name === "AssertionError")
11579
- return errorObject;
11580
- for (const key of Object.getOwnPropertyNames(e)) {
11581
- if (!skipErrorProperties.has(key))
11582
- errorObject[key] = e[key];
11583
- }
11584
- return errorObject;
11585
- }
11586
- const esmErrors = [
11587
- "Cannot use import statement outside a module",
11588
- "Unexpected token 'export'"
11589
- ];
11590
- function handleImportOutsideModuleError(stack, ctx) {
11591
- if (!esmErrors.some((e) => stack.includes(e)))
11592
- return;
11593
- const path = normalize(stack.split("\n")[0].trim());
11594
- let name = path.split("/node_modules/").pop() || "";
11595
- if (name == null ? void 0 : name.startsWith("@"))
11596
- name = name.split("/").slice(0, 2).join("/");
11597
- else
11598
- name = name.split("/")[0];
11599
- ctx.logger.error(c.yellow(
11600
- `Module ${path} seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package ${c.bold(`"${name}"`)} asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
11601
-
11602
- As a temporary workaround you can try to inline the package by updating your config:
11603
-
11604
- ` + c.gray(c.dim("// vitest.config.js")) + "\n" + c.green(`export default {
11605
- test: {
11606
- deps: {
11607
- inline: [
11608
- ${c.yellow(c.bold(`"${name}"`))}
11609
- ]
11610
- }
11611
- }
11612
- }
11613
- `)
11614
- ));
11615
- }
11616
- function displayDiff(diff, console) {
11617
- console.error(diff);
11618
- }
11619
- function printErrorMessage(error, logger) {
11620
- const errorName = error.name || error.nameStr || "Unknown Error";
11621
- logger.error(c.red(`${c.bold(errorName)}: ${error.message}`));
11622
- }
11623
- function printStack(ctx, stack, highlight, errorProperties, onStack) {
11624
- const logger = ctx.logger;
11625
- for (const frame of stack) {
11626
- const color = frame === highlight ? c.yellow : c.gray;
11627
- const path = relative(ctx.config.root, frame.file);
11628
- logger.error(color(` ${c.dim(F_POINTER)} ${[frame.method, c.dim(`${path}:${frame.line}:${frame.column}`)].filter(Boolean).join(" ")}`));
11629
- onStack == null ? void 0 : onStack(frame);
11630
- }
11631
- if (stack.length)
11632
- logger.error();
11633
- const hasProperties = Object.keys(errorProperties).length > 0;
11634
- if (hasProperties) {
11635
- logger.error(c.red(c.dim(divider())));
11636
- const propertiesString = stringify$5(errorProperties, 10, { printBasicPrototype: false });
11637
- logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
11638
- }
11639
- }
11640
- function generateCodeFrame(source, indent = 0, lineNumber, columnNumber, range = 2) {
11641
- var _a;
11642
- const start = positionToOffset(source, lineNumber, columnNumber);
11643
- const end = start;
11644
- const lines = source.split(lineSplitRE);
11645
- let count = 0;
11646
- let res = [];
11647
- const columns = ((_a = process.stdout) == null ? void 0 : _a.columns) || 80;
11648
- function lineNo(no = "") {
11649
- return c.gray(`${String(no).padStart(3, " ")}| `);
11650
- }
11651
- for (let i = 0; i < lines.length; i++) {
11652
- count += lines[i].length + 1;
11653
- if (count >= start) {
11654
- for (let j = i - range; j <= i + range || end > count; j++) {
11655
- if (j < 0 || j >= lines.length)
11656
- continue;
11657
- const lineLength = lines[j].length;
11658
- if (lineLength > 200)
11659
- return "";
11660
- res.push(lineNo(j + 1) + cliTruncate(lines[j].replace(/\t/g, " "), columns - 5 - indent));
11661
- if (j === i) {
11662
- const pad = start - (count - lineLength);
11663
- const length = Math.max(1, end > count ? lineLength - pad : end - start);
11664
- res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
11665
- } else if (j > i) {
11666
- if (end > count) {
11667
- const length = Math.max(1, Math.min(end - count, lineLength));
11668
- res.push(lineNo() + c.red("^".repeat(length)));
11669
- }
11670
- count += lineLength + 1;
11671
- }
11672
- }
11673
- break;
11674
- }
11675
- }
11676
- if (indent)
11677
- res = res.map((line) => " ".repeat(indent) + line);
11678
- return res.join("\n");
11679
- }
11680
-
11681
- class Logger {
11682
- constructor(ctx, console = globalThis.console) {
11683
- this.ctx = ctx;
11684
- this.console = console;
11685
- this.outputStream = process.stdout;
11686
- this.errorStream = process.stderr;
11687
- this.logUpdate = createLogUpdate(process.stdout);
11688
- }
11689
- log(...args) {
11690
- this._clearScreen();
11691
- this.console.log(...args);
11692
- }
11693
- error(...args) {
11694
- this._clearScreen();
11695
- this.console.error(...args);
11696
- }
11697
- warn(...args) {
11698
- this._clearScreen();
11699
- this.console.warn(...args);
11700
- }
11701
- clearFullScreen(message) {
11702
- if (this.ctx.server.config.clearScreen === false) {
11703
- this.console.log(message);
11704
- return;
11705
- }
11706
- this.console.log(`\x1Bc${message}`);
11707
- }
11708
- clearScreen(message, force = false) {
11709
- if (this.ctx.server.config.clearScreen === false) {
11710
- this.console.log(message);
11711
- return;
11712
- }
11713
- this._clearScreenPending = message;
11714
- if (force)
11715
- this._clearScreen();
11716
- }
11717
- _clearScreen() {
11718
- if (this._clearScreenPending == null)
11719
- return;
11720
- const log = this._clearScreenPending;
11721
- this._clearScreenPending = void 0;
11722
- this.console.log(`\x1B[1;1H\x1B[J${log}`);
11723
- }
11724
- printError(err, fullStack = false, type) {
11725
- return printError(err, this.ctx, {
11726
- fullStack,
11727
- type,
11728
- showCodeFrame: true
11729
- });
11730
- }
11731
- printNoTestFound(filters) {
11732
- const config = this.ctx.config;
11733
- const comma = c.dim(", ");
11734
- if (filters == null ? void 0 : filters.length)
11735
- this.console.error(c.dim("filter: ") + c.yellow(filters.join(comma)));
11736
- if (config.include)
11737
- this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
11738
- if (config.exclude)
11739
- this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
11740
- if (config.watchExclude)
11741
- this.console.error(c.dim("watch exclude: ") + c.yellow(config.watchExclude.join(comma)));
11742
- if (config.passWithNoTests)
11743
- this.log(`No ${config.mode} files found, exiting with code 0
11744
- `);
11745
- else
11746
- this.error(c.red(`
11747
- No ${config.mode} files found, exiting with code 1`));
11748
- }
11749
- printBanner() {
11750
- var _a, _b;
11751
- this.log();
11752
- const versionTest = this.ctx.config.watch ? c.blue(`v${version}`) : c.cyan(`v${version}`);
11753
- const mode = this.ctx.config.watch ? c.blue(" DEV ") : c.cyan(" RUN ");
11754
- this.log(`${c.inverse(c.bold(mode))} ${versionTest} ${c.gray(this.ctx.config.root)}`);
11755
- if (this.ctx.config.sequence.sequencer === RandomSequencer)
11756
- this.log(c.gray(` Running tests with seed "${this.ctx.config.sequence.seed}"`));
11757
- this.ctx.projects.forEach((project) => {
11758
- var _a2;
11759
- if (!project.browser)
11760
- return;
11761
- const name = project.getName();
11762
- const output = project.isCore() ? "" : ` [${name}]`;
11763
- this.log(c.dim(c.green(` ${output} Browser runner started at http://${((_a2 = project.config.browser.api) == null ? void 0 : _a2.host) || "localhost"}:${c.bold(`${project.browser.config.server.port}`)}`)));
11764
- });
11765
- if (this.ctx.config.ui)
11766
- this.log(c.dim(c.green(` UI started at http://${((_a = this.ctx.config.api) == null ? void 0 : _a.host) || "localhost"}:${c.bold(`${this.ctx.server.config.server.port}`)}${this.ctx.config.uiBase}`)));
11767
- else if (this.ctx.config.api)
11768
- this.log(c.dim(c.green(` API started at http://${((_b = this.ctx.config.api) == null ? void 0 : _b.host) || "localhost"}:${c.bold(`${this.ctx.config.api.port}`)}`)));
11769
- if (this.ctx.coverageProvider)
11770
- this.log(c.dim(" Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
11771
- this.log();
11772
- }
11773
- async printUnhandledErrors(errors) {
11774
- const errorMessage = c.red(c.bold(
11775
- `
11776
- Vitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
11777
- This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`
11778
- ));
11779
- this.log(c.red(divider(c.bold(c.inverse(" Unhandled Errors ")))));
11780
- this.log(errorMessage);
11781
- await Promise.all(errors.map(async (err) => {
11782
- await this.printError(err, true, err.type || "Unhandled Error");
11783
- }));
11784
- this.log(c.red(divider()));
11785
- }
11786
- async printSourceTypeErrors(errors) {
11787
- const errorMessage = c.red(c.bold(
11788
- `
11789
- Vitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related to your test files.`
11790
- ));
11791
- this.log(c.red(divider(c.bold(c.inverse(" Source Errors ")))));
11792
- this.log(errorMessage);
11793
- await Promise.all(errors.map(async (err) => {
11794
- await this.printError(err, true);
11795
- }));
11796
- this.log(c.red(divider()));
11797
- }
11798
- }
11799
-
11800
- function CoverageTransform(ctx) {
11801
- return {
11802
- name: "vitest:coverage-transform",
11803
- transform(srcCode, id) {
11804
- var _a, _b;
11805
- return (_b = (_a = ctx.coverageProvider) == null ? void 0 : _a.onFileTransform) == null ? void 0 : _b.call(_a, srcCode, normalizeRequestId(id), this);
11806
- }
11807
- };
11808
- }
11809
-
11810
- async function createBrowserServer(project, options) {
11811
- const root = project.config.root;
11812
- await ensurePackageInstalled("@vitest/browser", root);
11813
- const configPath = options.config === false ? false : options.config ? resolve$2(root, options.config) : await findUp(configFiles, { cwd: root });
11814
- const server = await createServer({
11815
- logLevel: "error",
11816
- mode: project.config.mode,
11817
- configFile: configPath,
11818
- // watch is handled by Vitest
11819
- server: {
11820
- hmr: false,
11821
- watch: {
11822
- ignored: ["**/**"]
11823
- }
11824
- },
11825
- plugins: [
11826
- (await import('@vitest/browser')).default("/"),
11827
- CoverageTransform(project.ctx),
11828
- {
11829
- enforce: "post",
11830
- name: "vitest:browser:config",
11831
- async config(config) {
11832
- var _a, _b;
11833
- const server2 = resolveApiServerConfig(((_a = config.test) == null ? void 0 : _a.browser) || {}) || {
11834
- port: defaultBrowserPort
11835
- };
11836
- config.server = server2;
11837
- config.server.fs = { strict: false };
11838
- return {
11839
- resolve: {
11840
- alias: (_b = config.test) == null ? void 0 : _b.alias
11841
- }
11842
- };
11843
- }
11844
- }
11845
- ]
11846
- });
11847
- await server.listen();
11848
- await server.watcher.close();
11849
- (await import('./chunk-api-setup.c93e5069.js')).setup(project, server);
11850
- return server;
11851
- }
11852
-
11853
- const playwrightBrowsers = ["firefox", "webkit", "chromium"];
11854
- class PlaywrightBrowserProvider {
11855
- constructor() {
11856
- this.name = "playwright";
11857
- this.cachedBrowser = null;
11858
- }
11859
- getSupportedBrowsers() {
11860
- return playwrightBrowsers;
11861
- }
11862
- async initialize(ctx, { browser }) {
11863
- this.ctx = ctx;
11864
- this.browser = browser;
11865
- const root = this.ctx.config.root;
11866
- if (!await ensurePackageInstalled("playwright", root))
11867
- throw new Error('Cannot find "playwright" package. Please install it manually.');
11868
- }
11869
- async openBrowser() {
11870
- if (this.cachedBrowser)
11871
- return this.cachedBrowser;
11872
- const options = this.ctx.config.browser;
11873
- const playwright = await import('playwright');
11874
- const playwrightInstance = await playwright[this.browser].launch({ headless: options.headless });
11875
- this.cachedBrowser = await playwrightInstance.newPage();
11876
- this.cachedBrowser.on("close", () => {
11877
- playwrightInstance.close();
11878
- });
11879
- return this.cachedBrowser;
11880
- }
11881
- async openPage(url) {
11882
- const browserInstance = await this.openBrowser();
11883
- await browserInstance.goto(url);
11884
- }
11885
- async close() {
11886
- var _a;
11887
- await ((_a = this.cachedBrowser) == null ? void 0 : _a.close());
11888
- process.exit();
11889
- }
11890
- }
11891
-
11892
- const webdriverBrowsers = ["firefox", "chrome", "edge", "safari"];
11893
- class WebdriverBrowserProvider {
11894
- constructor() {
11895
- this.name = "webdriverio";
11896
- this.cachedBrowser = null;
11897
- this.stopSafari = () => {
11898
- };
11899
- }
11900
- getSupportedBrowsers() {
11901
- return webdriverBrowsers;
11902
- }
11903
- async initialize(ctx, { browser }) {
11904
- this.ctx = ctx;
11905
- this.browser = browser;
11906
- const root = this.ctx.config.root;
11907
- if (!await ensurePackageInstalled("webdriverio", root))
11908
- throw new Error('Cannot find "webdriverio" package. Please install it manually.');
11909
- if (browser === "safari" && !await ensurePackageInstalled("safaridriver", root))
11910
- throw new Error('Cannot find "safaridriver" package. Please install it manually.');
11911
- }
11912
- async openBrowser() {
11913
- if (this.cachedBrowser)
11914
- return this.cachedBrowser;
11915
- const options = this.ctx.config.browser;
11916
- if (this.browser === "safari") {
11917
- const safaridriver = await import('safaridriver');
11918
- safaridriver.start({ diagnose: true });
11919
- this.stopSafari = () => safaridriver.stop();
11920
- process.on("beforeExit", () => {
11921
- safaridriver.stop();
11922
- });
11923
- }
11924
- const { remote } = await import('webdriverio');
11925
- this.cachedBrowser = await remote({
11926
- logLevel: "error",
11927
- capabilities: {
11928
- "browserName": this.browser,
11929
- "wdio:devtoolsOptions": { headless: options.headless }
11930
- }
11931
- });
11932
- return this.cachedBrowser;
11933
- }
11934
- async openPage(url) {
11935
- const browserInstance = await this.openBrowser();
11936
- await browserInstance.url(url);
11937
- }
11938
- async close() {
11939
- var _a, _b, _c;
11940
- await Promise.all([
11941
- this.stopSafari(),
11942
- ((_a = this.cachedBrowser) == null ? void 0 : _a.sessionId) ? (_c = (_b = this.cachedBrowser) == null ? void 0 : _b.deleteSession) == null ? void 0 : _c.call(_b) : null
11943
- ]);
11944
- process.exit();
11945
- }
11946
- }
11947
-
11948
- async function getBrowserProvider(options, loader) {
11949
- switch (options.provider) {
11950
- case void 0:
11951
- case "webdriverio":
11952
- return WebdriverBrowserProvider;
11953
- case "playwright":
11954
- return PlaywrightBrowserProvider;
11955
- }
11956
- let customProviderModule;
11957
- try {
11958
- customProviderModule = await loader.executeId(options.provider);
11959
- } catch (error) {
11960
- throw new Error(`Failed to load custom BrowserProvider from ${options.provider}`, { cause: error });
11961
- }
11962
- if (customProviderModule.default == null)
11963
- throw new Error(`Custom BrowserProvider loaded from ${options.provider} was not the default export`);
11964
- return customProviderModule.default;
11965
- }
11966
-
11967
- function generateCssFilenameHash(filepath) {
11968
- return createHash("md5").update(filepath).digest("hex").slice(0, 6);
11969
- }
11970
- function generateScopedClassName(strategy, name, filename) {
11971
- if (strategy === "scoped")
11972
- return null;
11973
- if (strategy === "non-scoped")
11974
- return name;
11975
- const hash = generateCssFilenameHash(filename);
11976
- return `_${name}_${hash}`;
11977
- }
11978
-
11979
- const cssLangs = "\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)";
11980
- const cssLangRE = new RegExp(cssLangs);
11981
- const cssModuleRE = new RegExp(`\\.module${cssLangs}`);
11982
- function isCSS(id) {
11983
- return cssLangRE.test(id);
11984
- }
11985
- function isCSSModule(id) {
11986
- return cssModuleRE.test(id);
11987
- }
11988
- function getCSSModuleProxyReturn(strategy, filename) {
11989
- if (strategy === "non-scoped")
11990
- return "style";
11991
- const hash = generateCssFilenameHash(filename);
11992
- return `\`_\${style}_${hash}\``;
11993
- }
11994
- function CSSEnablerPlugin(ctx) {
11995
- const shouldProcessCSS = (id) => {
11996
- const { css } = ctx.config;
11997
- if (typeof css === "boolean")
11998
- return css;
11999
- if (toArray(css.exclude).some((re) => re.test(id)))
12000
- return false;
12001
- if (toArray(css.include).some((re) => re.test(id)))
12002
- return true;
12003
- return false;
12004
- };
12005
- return [
12006
- {
12007
- name: "vitest:css-disable",
12008
- enforce: "pre",
12009
- transform(code, id) {
12010
- if (!isCSS(id))
12011
- return;
12012
- if (!shouldProcessCSS(id))
12013
- return { code: "" };
12014
- }
12015
- },
12016
- {
12017
- name: "vitest:css-empty-post",
12018
- enforce: "post",
12019
- transform(_, id) {
12020
- var _a;
12021
- if (!isCSS(id) || shouldProcessCSS(id))
12022
- return;
12023
- if (isCSSModule(id)) {
12024
- const scopeStrategy = typeof ctx.config.css !== "boolean" && ((_a = ctx.config.css.modules) == null ? void 0 : _a.classNameStrategy) || "stable";
12025
- const proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id));
12026
- const code = `export default new Proxy(Object.create(null), {
12027
- get(_, style) {
12028
- return ${proxyReturn};
12029
- },
12030
- })`;
12031
- return { code };
12032
- }
12033
- return { code: 'export default ""' };
12034
- }
12035
- }
12036
- ];
12037
- }
12038
-
12039
- function EnvReplacerPlugin() {
12040
- return {
12041
- name: "vitest:env-replacer",
12042
- enforce: "pre",
12043
- transform(code, id) {
12044
- if (!/\bimport\.meta\.env\b/g.test(code))
12045
- return null;
12046
- let s = null;
12047
- const envs = stripLiteral(code).matchAll(/\bimport\.meta\.env\b/g);
12048
- for (const env of envs) {
12049
- s || (s = new MagicString(code));
12050
- const startIndex = env.index;
12051
- const endIndex = startIndex + env[0].length;
12052
- s.overwrite(startIndex, endIndex, "process.env");
12053
- }
12054
- if (s) {
12055
- return {
12056
- code: s.toString(),
12057
- map: s.generateMap({
12058
- hires: true,
12059
- // Remove possible query parameters, e.g. vue's "?vue&type=script&src=true&lang.ts"
12060
- source: cleanUrl(id)
12061
- })
12062
- };
12063
- }
12064
- }
12065
- };
12066
- }
12067
-
12068
- async function loadGlobalSetupFiles(project) {
12069
- var _a;
12070
- const server = project.server;
12071
- const runner = project.runner;
12072
- const globalSetupFiles = toArray((_a = server.config.test) == null ? void 0 : _a.globalSetup);
12073
- return Promise.all(globalSetupFiles.map((file) => loadGlobalSetupFile(file, runner)));
12074
- }
12075
- async function loadGlobalSetupFile(file, runner) {
12076
- const m = await runner.executeFile(file);
12077
- for (const exp of ["default", "setup", "teardown"]) {
12078
- if (m[exp] != null && typeof m[exp] !== "function")
12079
- throw new Error(`invalid export in globalSetup file ${file}: ${exp} must be a function`);
12080
- }
12081
- if (m.default) {
12082
- return {
12083
- file,
12084
- setup: m.default
12085
- };
12086
- } else if (m.setup || m.teardown) {
12087
- return {
12088
- file,
12089
- setup: m.setup,
12090
- teardown: m.teardown
12091
- };
12092
- } else {
12093
- throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
12094
- }
12095
11317
  }
12096
- function GlobalSetupPlugin(project, logger) {
12097
- let globalSetupFiles;
12098
- return {
12099
- name: "vitest:global-setup-plugin",
12100
- enforce: "pre",
12101
- async buildStart() {
12102
- var _a, _b;
12103
- if (!((_a = project.server.config.test) == null ? void 0 : _a.globalSetup))
12104
- return;
12105
- globalSetupFiles = await loadGlobalSetupFiles(project);
12106
- try {
12107
- for (const globalSetupFile of globalSetupFiles) {
12108
- const teardown = await ((_b = globalSetupFile.setup) == null ? void 0 : _b.call(globalSetupFile));
12109
- if (teardown == null || !!globalSetupFile.teardown)
11318
+ /**
11319
+ * The path can have empty directories "//", unneeded parents "foo/..", or current directory
11320
+ * "foo/.". We need to normalize to a standard representation.
11321
+ */
11322
+ function normalizePath(url, type) {
11323
+ const rel = type <= UrlType.RelativePath;
11324
+ const pieces = url.path.split('/');
11325
+ // We need to preserve the first piece always, so that we output a leading slash. The item at
11326
+ // pieces[0] is an empty string.
11327
+ let pointer = 1;
11328
+ // Positive is the number of real directories we've output, used for popping a parent directory.
11329
+ // Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
11330
+ let positive = 0;
11331
+ // We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
11332
+ // generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
11333
+ // real directory, we won't need to append, unless the other conditions happen again.
11334
+ let addTrailingSlash = false;
11335
+ for (let i = 1; i < pieces.length; i++) {
11336
+ const piece = pieces[i];
11337
+ // An empty directory, could be a trailing slash, or just a double "//" in the path.
11338
+ if (!piece) {
11339
+ addTrailingSlash = true;
12110
11340
  continue;
12111
- if (typeof teardown !== "function")
12112
- throw new Error(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
12113
- globalSetupFile.teardown = teardown;
12114
11341
  }
12115
- } catch (e) {
12116
- logger.error(`
12117
- ${c.red(divider(c.bold(c.inverse(" Error during global setup "))))}`);
12118
- await logger.printError(e);
12119
- process.exit(1);
12120
- }
12121
- },
12122
- async buildEnd() {
12123
- var _a;
12124
- if (globalSetupFiles == null ? void 0 : globalSetupFiles.length) {
12125
- for (const globalSetupFile of globalSetupFiles.reverse()) {
12126
- try {
12127
- await ((_a = globalSetupFile.teardown) == null ? void 0 : _a.call(globalSetupFile));
12128
- } catch (error) {
12129
- logger.error(`error during global teardown of ${globalSetupFile.file}`, error);
12130
- }
11342
+ // If we encounter a real directory, then we don't need to append anymore.
11343
+ addTrailingSlash = false;
11344
+ // A current directory, which we can always drop.
11345
+ if (piece === '.')
11346
+ continue;
11347
+ // A parent directory, we need to see if there are any real directories we can pop. Else, we
11348
+ // have an excess of parents, and we'll need to keep the "..".
11349
+ if (piece === '..') {
11350
+ if (positive) {
11351
+ addTrailingSlash = true;
11352
+ positive--;
11353
+ pointer--;
11354
+ }
11355
+ else if (rel) {
11356
+ // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
11357
+ // URL, protocol relative URL, or an absolute path, we don't need to keep excess.
11358
+ pieces[pointer++] = piece;
11359
+ }
11360
+ continue;
12131
11361
  }
12132
- }
11362
+ // We've encountered a real directory. Move it to the next insertion pointer, which accounts for
11363
+ // any popped or dropped directories.
11364
+ pieces[pointer++] = piece;
11365
+ positive++;
12133
11366
  }
12134
- };
11367
+ let path = '';
11368
+ for (let i = 1; i < pointer; i++) {
11369
+ path += '/' + pieces[i];
11370
+ }
11371
+ if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
11372
+ path += '/';
11373
+ }
11374
+ url.path = path;
12135
11375
  }
12136
-
12137
- function WorkspaceVitestPlugin(project, options) {
12138
- return [
12139
- {
12140
- name: "vitest:project",
12141
- enforce: "pre",
12142
- options() {
12143
- this.meta.watchMode = false;
12144
- },
12145
- // TODO: refactor so we don't have the same code here and in plugins/index.ts
12146
- config(viteConfig) {
12147
- var _a, _b, _c;
12148
- if (viteConfig.define) {
12149
- delete viteConfig.define["import.meta.vitest"];
12150
- delete viteConfig.define["process.env"];
12151
- }
12152
- const env = {};
12153
- for (const key in viteConfig.define) {
12154
- const val = viteConfig.define[key];
12155
- let replacement;
12156
- try {
12157
- replacement = typeof val === "string" ? JSON.parse(val) : val;
12158
- } catch {
12159
- continue;
12160
- }
12161
- if (key.startsWith("import.meta.env.")) {
12162
- const envKey = key.slice("import.meta.env.".length);
12163
- env[envKey] = replacement;
12164
- delete viteConfig.define[key];
12165
- } else if (key.startsWith("process.env.")) {
12166
- const envKey = key.slice("process.env.".length);
12167
- env[envKey] = replacement;
12168
- delete viteConfig.define[key];
12169
- }
12170
- }
12171
- const testConfig = viteConfig.test || {};
12172
- const root = testConfig.root || viteConfig.root || options.root;
12173
- let name = testConfig.name;
12174
- if (!name) {
12175
- if (typeof options.workspacePath === "string")
12176
- name = dirname(options.workspacePath).split("/").pop();
12177
- else
12178
- name = options.workspacePath.toString();
12179
- }
12180
- const config = {
12181
- root,
12182
- resolve: {
12183
- // by default Vite resolves `module` field, which not always a native ESM module
12184
- // setting this option can bypass that and fallback to cjs version
12185
- mainFields: [],
12186
- alias: testConfig.alias,
12187
- conditions: ["node"],
12188
- // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
12189
- // @ts-ignore we support Vite ^3.0, but browserField is available in Vite ^3.2
12190
- browserField: false
12191
- },
12192
- esbuild: {
12193
- sourcemap: "external",
12194
- // Enables using ignore hint for coverage providers with @preserve keyword
12195
- legalComments: "inline"
12196
- },
12197
- server: {
12198
- // disable watch mode in workspaces,
12199
- // because it is handled by the top-level watcher
12200
- watch: {
12201
- ignored: ["**/*"],
12202
- depth: 0,
12203
- persistent: false
12204
- },
12205
- open: false,
12206
- hmr: false,
12207
- preTransformRequests: false
12208
- },
12209
- test: {
12210
- env,
12211
- name
12212
- }
12213
- };
12214
- const classNameStrategy = typeof testConfig.css !== "boolean" && ((_b = (_a = testConfig.css) == null ? void 0 : _a.modules) == null ? void 0 : _b.classNameStrategy) || "stable";
12215
- if (classNameStrategy !== "scoped") {
12216
- config.css ?? (config.css = {});
12217
- (_c = config.css).modules ?? (_c.modules = {});
12218
- if (config.css.modules) {
12219
- config.css.modules.generateScopedName = (name2, filename) => {
12220
- const root2 = project.config.root;
12221
- return generateScopedClassName(classNameStrategy, name2, relative(root2, filename));
12222
- };
12223
- }
11376
+ /**
11377
+ * Attempts to resolve `input` URL/path relative to `base`.
11378
+ */
11379
+ function resolve$1(input, base) {
11380
+ if (!input && !base)
11381
+ return '';
11382
+ const url = parseUrl(input);
11383
+ let inputType = url.type;
11384
+ if (base && inputType !== UrlType.Absolute) {
11385
+ const baseUrl = parseUrl(base);
11386
+ const baseType = baseUrl.type;
11387
+ switch (inputType) {
11388
+ case UrlType.Empty:
11389
+ url.hash = baseUrl.hash;
11390
+ // fall through
11391
+ case UrlType.Hash:
11392
+ url.query = baseUrl.query;
11393
+ // fall through
11394
+ case UrlType.Query:
11395
+ case UrlType.RelativePath:
11396
+ mergePaths(url, baseUrl);
11397
+ // fall through
11398
+ case UrlType.AbsolutePath:
11399
+ // The host, user, and port are joined, you can't copy one without the others.
11400
+ url.user = baseUrl.user;
11401
+ url.host = baseUrl.host;
11402
+ url.port = baseUrl.port;
11403
+ // fall through
11404
+ case UrlType.SchemeRelative:
11405
+ // The input doesn't have a schema at least, so we need to copy at least that over.
11406
+ url.scheme = baseUrl.scheme;
12224
11407
  }
12225
- return config;
12226
- },
12227
- async configureServer(server) {
12228
- try {
12229
- const options2 = deepMerge(
12230
- {},
12231
- configDefaults,
12232
- server.config.test || {}
12233
- );
12234
- await project.setServer(options2, server);
12235
- } catch (err) {
12236
- await project.ctx.logger.printError(err, true);
12237
- process.exit(1);
11408
+ if (baseType > inputType)
11409
+ inputType = baseType;
11410
+ }
11411
+ normalizePath(url, inputType);
11412
+ const queryHash = url.query + url.hash;
11413
+ switch (inputType) {
11414
+ // This is impossible, because of the empty checks at the start of the function.
11415
+ // case UrlType.Empty:
11416
+ case UrlType.Hash:
11417
+ case UrlType.Query:
11418
+ return queryHash;
11419
+ case UrlType.RelativePath: {
11420
+ // The first char is always a "/", and we need it to be relative.
11421
+ const path = url.path.slice(1);
11422
+ if (!path)
11423
+ return queryHash || '.';
11424
+ if (isRelative(base || input) && !isRelative(path)) {
11425
+ // If base started with a leading ".", or there is no base and input started with a ".",
11426
+ // then we need to ensure that the relative path starts with a ".". We don't know if
11427
+ // relative starts with a "..", though, so check before prepending.
11428
+ return './' + path + queryHash;
11429
+ }
11430
+ return path + queryHash;
12238
11431
  }
12239
- await server.watcher.close();
12240
- }
12241
- },
12242
- EnvReplacerPlugin(),
12243
- ...CSSEnablerPlugin(project),
12244
- CoverageTransform(project.ctx),
12245
- GlobalSetupPlugin(project, project.ctx.logger)
12246
- ];
11432
+ case UrlType.AbsolutePath:
11433
+ return url.path + queryHash;
11434
+ default:
11435
+ return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
11436
+ }
12247
11437
  }
12248
11438
 
12249
- const comma = ','.charCodeAt(0);
12250
- const semicolon = ';'.charCodeAt(0);
12251
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
12252
- const intToChar = new Uint8Array(64); // 64 possible chars.
12253
- const charToInt = new Uint8Array(128); // z is 122 in ASCII
12254
- for (let i = 0; i < chars.length; i++) {
12255
- const c = chars.charCodeAt(i);
12256
- intToChar[i] = c;
12257
- charToInt[c] = i;
11439
+ function resolve(input, base) {
11440
+ // The base is always treated as a directory, if it's not empty.
11441
+ // https://github.com/mozilla/source-map/blob/8cb3ee57/lib/util.js#L327
11442
+ // https://github.com/chromium/chromium/blob/da4adbb3/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js#L400-L401
11443
+ if (base && !base.endsWith('/'))
11444
+ base += '/';
11445
+ return resolve$1(input, base);
12258
11446
  }
12259
- // Provide a fallback for older environments.
12260
- const td = typeof TextDecoder !== 'undefined'
12261
- ? /* #__PURE__ */ new TextDecoder()
12262
- : typeof Buffer !== 'undefined'
12263
- ? {
12264
- decode(buf) {
12265
- const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
12266
- return out.toString();
12267
- },
12268
- }
12269
- : {
12270
- decode(buf) {
12271
- let out = '';
12272
- for (let i = 0; i < buf.length; i++) {
12273
- out += String.fromCharCode(buf[i]);
12274
- }
12275
- return out;
12276
- },
12277
- };
12278
- function decode(mappings) {
12279
- const state = new Int32Array(5);
12280
- const decoded = [];
12281
- let index = 0;
12282
- do {
12283
- const semi = indexOf(mappings, index);
12284
- const line = [];
12285
- let sorted = true;
12286
- let lastCol = 0;
12287
- state[0] = 0;
12288
- for (let i = index; i < semi; i++) {
12289
- let seg;
12290
- i = decodeInteger(mappings, i, state, 0); // genColumn
12291
- const col = state[0];
12292
- if (col < lastCol)
12293
- sorted = false;
12294
- lastCol = col;
12295
- if (hasMoreVlq(mappings, i, semi)) {
12296
- i = decodeInteger(mappings, i, state, 1); // sourcesIndex
12297
- i = decodeInteger(mappings, i, state, 2); // sourceLine
12298
- i = decodeInteger(mappings, i, state, 3); // sourceColumn
12299
- if (hasMoreVlq(mappings, i, semi)) {
12300
- i = decodeInteger(mappings, i, state, 4); // namesIndex
12301
- seg = [col, state[1], state[2], state[3], state[4]];
12302
- }
12303
- else {
12304
- seg = [col, state[1], state[2], state[3]];
12305
- }
12306
- }
12307
- else {
12308
- seg = [col];
12309
- }
12310
- line.push(seg);
11447
+
11448
+ /**
11449
+ * Removes everything after the last "/", but leaves the slash.
11450
+ */
11451
+ function stripFilename(path) {
11452
+ if (!path)
11453
+ return '';
11454
+ const index = path.lastIndexOf('/');
11455
+ return path.slice(0, index + 1);
11456
+ }
11457
+
11458
+ const COLUMN = 0;
11459
+ const SOURCES_INDEX = 1;
11460
+ const SOURCE_LINE = 2;
11461
+ const SOURCE_COLUMN = 3;
11462
+ const REV_GENERATED_LINE = 1;
11463
+ const REV_GENERATED_COLUMN = 2;
11464
+
11465
+ function maybeSort(mappings, owned) {
11466
+ const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
11467
+ if (unsortedIndex === mappings.length)
11468
+ return mappings;
11469
+ // If we own the array (meaning we parsed it from JSON), then we're free to directly mutate it. If
11470
+ // not, we do not want to modify the consumer's input array.
11471
+ if (!owned)
11472
+ mappings = mappings.slice();
11473
+ for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
11474
+ mappings[i] = sortSegments(mappings[i], owned);
11475
+ }
11476
+ return mappings;
11477
+ }
11478
+ function nextUnsortedSegmentLine(mappings, start) {
11479
+ for (let i = start; i < mappings.length; i++) {
11480
+ if (!isSorted(mappings[i]))
11481
+ return i;
11482
+ }
11483
+ return mappings.length;
11484
+ }
11485
+ function isSorted(line) {
11486
+ for (let j = 1; j < line.length; j++) {
11487
+ if (line[j][COLUMN] < line[j - 1][COLUMN]) {
11488
+ return false;
12311
11489
  }
12312
- if (!sorted)
12313
- sort(line);
12314
- decoded.push(line);
12315
- index = semi + 1;
12316
- } while (index <= mappings.length);
12317
- return decoded;
11490
+ }
11491
+ return true;
12318
11492
  }
12319
- function indexOf(mappings, index) {
12320
- const idx = mappings.indexOf(';', index);
12321
- return idx === -1 ? mappings.length : idx;
11493
+ function sortSegments(line, owned) {
11494
+ if (!owned)
11495
+ line = line.slice();
11496
+ return line.sort(sortComparator);
12322
11497
  }
12323
- function decodeInteger(mappings, pos, state, j) {
12324
- let value = 0;
12325
- let shift = 0;
12326
- let integer = 0;
12327
- do {
12328
- const c = mappings.charCodeAt(pos++);
12329
- integer = charToInt[c];
12330
- value |= (integer & 31) << shift;
12331
- shift += 5;
12332
- } while (integer & 32);
12333
- const shouldNegate = value & 1;
12334
- value >>>= 1;
12335
- if (shouldNegate) {
12336
- value = -0x80000000 | -value;
11498
+ function sortComparator(a, b) {
11499
+ return a[COLUMN] - b[COLUMN];
11500
+ }
11501
+
11502
+ let found = false;
11503
+ /**
11504
+ * A binary search implementation that returns the index if a match is found.
11505
+ * If no match is found, then the left-index (the index associated with the item that comes just
11506
+ * before the desired index) is returned. To maintain proper sort order, a splice would happen at
11507
+ * the next index:
11508
+ *
11509
+ * ```js
11510
+ * const array = [1, 3];
11511
+ * const needle = 2;
11512
+ * const index = binarySearch(array, needle, (item, needle) => item - needle);
11513
+ *
11514
+ * assert.equal(index, 0);
11515
+ * array.splice(index + 1, 0, needle);
11516
+ * assert.deepEqual(array, [1, 2, 3]);
11517
+ * ```
11518
+ */
11519
+ function binarySearch(haystack, needle, low, high) {
11520
+ while (low <= high) {
11521
+ const mid = low + ((high - low) >> 1);
11522
+ const cmp = haystack[mid][COLUMN] - needle;
11523
+ if (cmp === 0) {
11524
+ found = true;
11525
+ return mid;
11526
+ }
11527
+ if (cmp < 0) {
11528
+ low = mid + 1;
11529
+ }
11530
+ else {
11531
+ high = mid - 1;
11532
+ }
12337
11533
  }
12338
- state[j] += value;
12339
- return pos;
11534
+ found = false;
11535
+ return low - 1;
12340
11536
  }
12341
- function hasMoreVlq(mappings, i, length) {
12342
- if (i >= length)
12343
- return false;
12344
- return mappings.charCodeAt(i) !== comma;
11537
+ function upperBound(haystack, needle, index) {
11538
+ for (let i = index + 1; i < haystack.length; index = i++) {
11539
+ if (haystack[i][COLUMN] !== needle)
11540
+ break;
11541
+ }
11542
+ return index;
12345
11543
  }
12346
- function sort(line) {
12347
- line.sort(sortComparator$1);
11544
+ function lowerBound(haystack, needle, index) {
11545
+ for (let i = index - 1; i >= 0; index = i--) {
11546
+ if (haystack[i][COLUMN] !== needle)
11547
+ break;
11548
+ }
11549
+ return index;
12348
11550
  }
12349
- function sortComparator$1(a, b) {
12350
- return a[0] - b[0];
11551
+ function memoizedState() {
11552
+ return {
11553
+ lastKey: -1,
11554
+ lastNeedle: -1,
11555
+ lastIndex: -1,
11556
+ };
12351
11557
  }
12352
- function encode(decoded) {
12353
- const state = new Int32Array(5);
12354
- const bufLength = 1024 * 16;
12355
- const subLength = bufLength - 36;
12356
- const buf = new Uint8Array(bufLength);
12357
- const sub = buf.subarray(0, subLength);
12358
- let pos = 0;
12359
- let out = '';
11558
+ /**
11559
+ * This overly complicated beast is just to record the last tested line/column and the resulting
11560
+ * index, allowing us to skip a few tests if mappings are monotonically increasing.
11561
+ */
11562
+ function memoizedBinarySearch(haystack, needle, state, key) {
11563
+ const { lastKey, lastNeedle, lastIndex } = state;
11564
+ let low = 0;
11565
+ let high = haystack.length - 1;
11566
+ if (key === lastKey) {
11567
+ if (needle === lastNeedle) {
11568
+ found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
11569
+ return lastIndex;
11570
+ }
11571
+ if (needle >= lastNeedle) {
11572
+ // lastIndex may be -1 if the previous needle was not found.
11573
+ low = lastIndex === -1 ? 0 : lastIndex;
11574
+ }
11575
+ else {
11576
+ high = lastIndex;
11577
+ }
11578
+ }
11579
+ state.lastKey = key;
11580
+ state.lastNeedle = needle;
11581
+ return (state.lastIndex = binarySearch(haystack, needle, low, high));
11582
+ }
11583
+
11584
+ // Rebuilds the original source files, with mappings that are ordered by source line/column instead
11585
+ // of generated line/column.
11586
+ function buildBySources(decoded, memos) {
11587
+ const sources = memos.map(buildNullArray);
12360
11588
  for (let i = 0; i < decoded.length; i++) {
12361
11589
  const line = decoded[i];
12362
- if (i > 0) {
12363
- if (pos === bufLength) {
12364
- out += td.decode(buf);
12365
- pos = 0;
12366
- }
12367
- buf[pos++] = semicolon;
11590
+ for (let j = 0; j < line.length; j++) {
11591
+ const seg = line[j];
11592
+ if (seg.length === 1)
11593
+ continue;
11594
+ const sourceIndex = seg[SOURCES_INDEX];
11595
+ const sourceLine = seg[SOURCE_LINE];
11596
+ const sourceColumn = seg[SOURCE_COLUMN];
11597
+ const originalSource = sources[sourceIndex];
11598
+ const originalLine = (originalSource[sourceLine] || (originalSource[sourceLine] = []));
11599
+ const memo = memos[sourceIndex];
11600
+ // The binary search either found a match, or it found the left-index just before where the
11601
+ // segment should go. Either way, we want to insert after that. And there may be multiple
11602
+ // generated segments associated with an original location, so there may need to move several
11603
+ // indexes before we find where we need to insert.
11604
+ const index = upperBound(originalLine, sourceColumn, memoizedBinarySearch(originalLine, sourceColumn, memo, sourceLine));
11605
+ insert(originalLine, (memo.lastIndex = index + 1), [sourceColumn, i, seg[COLUMN]]);
11606
+ }
11607
+ }
11608
+ return sources;
11609
+ }
11610
+ function insert(array, index, value) {
11611
+ for (let i = array.length; i > index; i--) {
11612
+ array[i] = array[i - 1];
11613
+ }
11614
+ array[index] = value;
11615
+ }
11616
+ // Null arrays allow us to use ordered index keys without actually allocating contiguous memory like
11617
+ // a real array. We use a null-prototype object to avoid prototype pollution and deoptimizations.
11618
+ // Numeric properties on objects are magically sorted in ascending order by the engine regardless of
11619
+ // the insertion order. So, by setting any numeric keys, even out of order, we'll get ascending
11620
+ // order when iterating with for-in.
11621
+ function buildNullArray() {
11622
+ return { __proto__: null };
11623
+ }
11624
+
11625
+ const LINE_GTR_ZERO = '`line` must be greater than 0 (lines start at line 1)';
11626
+ const COL_GTR_EQ_ZERO = '`column` must be greater than or equal to 0 (columns start at column 0)';
11627
+ const LEAST_UPPER_BOUND = -1;
11628
+ const GREATEST_LOWER_BOUND = 1;
11629
+ /**
11630
+ * Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
11631
+ */
11632
+ let decodedMappings;
11633
+ /**
11634
+ * Finds the generated line/column position of the provided source/line/column source position.
11635
+ */
11636
+ let generatedPositionFor;
11637
+ class TraceMap {
11638
+ constructor(map, mapUrl) {
11639
+ const isString = typeof map === 'string';
11640
+ if (!isString && map._decodedMemo)
11641
+ return map;
11642
+ const parsed = (isString ? JSON.parse(map) : map);
11643
+ const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
11644
+ this.version = version;
11645
+ this.file = file;
11646
+ this.names = names;
11647
+ this.sourceRoot = sourceRoot;
11648
+ this.sources = sources;
11649
+ this.sourcesContent = sourcesContent;
11650
+ const from = resolve(sourceRoot || '', stripFilename(mapUrl));
11651
+ this.resolvedSources = sources.map((s) => resolve(s || '', from));
11652
+ const { mappings } = parsed;
11653
+ if (typeof mappings === 'string') {
11654
+ this._encoded = mappings;
11655
+ this._decoded = undefined;
12368
11656
  }
12369
- if (line.length === 0)
12370
- continue;
12371
- state[0] = 0;
12372
- for (let j = 0; j < line.length; j++) {
12373
- const segment = line[j];
12374
- // We can push up to 5 ints, each int can take at most 7 chars, and we
12375
- // may push a comma.
12376
- if (pos > subLength) {
12377
- out += td.decode(sub);
12378
- buf.copyWithin(0, subLength, pos);
12379
- pos -= subLength;
12380
- }
12381
- if (j > 0)
12382
- buf[pos++] = comma;
12383
- pos = encodeInteger(buf, pos, state, segment, 0); // genColumn
12384
- if (segment.length === 1)
12385
- continue;
12386
- pos = encodeInteger(buf, pos, state, segment, 1); // sourcesIndex
12387
- pos = encodeInteger(buf, pos, state, segment, 2); // sourceLine
12388
- pos = encodeInteger(buf, pos, state, segment, 3); // sourceColumn
12389
- if (segment.length === 4)
12390
- continue;
12391
- pos = encodeInteger(buf, pos, state, segment, 4); // namesIndex
11657
+ else {
11658
+ this._encoded = undefined;
11659
+ this._decoded = maybeSort(mappings, isString);
12392
11660
  }
11661
+ this._decodedMemo = memoizedState();
11662
+ this._bySources = undefined;
11663
+ this._bySourceMemos = undefined;
12393
11664
  }
12394
- return out + td.decode(buf.subarray(0, pos));
12395
11665
  }
12396
- function encodeInteger(buf, pos, state, segment, j) {
12397
- const next = segment[j];
12398
- let num = next - state[j];
12399
- state[j] = next;
12400
- num = num < 0 ? (-num << 1) | 1 : num << 1;
12401
- do {
12402
- let clamped = num & 0b011111;
12403
- num >>>= 5;
12404
- if (num > 0)
12405
- clamped |= 0b100000;
12406
- buf[pos++] = intToChar[clamped];
12407
- } while (num > 0);
12408
- return pos;
11666
+ (() => {
11667
+ decodedMappings = (map) => {
11668
+ return (map._decoded || (map._decoded = decode(map._encoded)));
11669
+ };
11670
+ generatedPositionFor = (map, { source, line, column, bias }) => {
11671
+ return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false);
11672
+ };
11673
+ function generatedPosition(map, source, line, column, bias, all) {
11674
+ line--;
11675
+ if (line < 0)
11676
+ throw new Error(LINE_GTR_ZERO);
11677
+ if (column < 0)
11678
+ throw new Error(COL_GTR_EQ_ZERO);
11679
+ const { sources, resolvedSources } = map;
11680
+ let sourceIndex = sources.indexOf(source);
11681
+ if (sourceIndex === -1)
11682
+ sourceIndex = resolvedSources.indexOf(source);
11683
+ if (sourceIndex === -1)
11684
+ return all ? [] : GMapping(null, null);
11685
+ const generated = (map._bySources || (map._bySources = buildBySources(decodedMappings(map), (map._bySourceMemos = sources.map(memoizedState)))));
11686
+ const segments = generated[sourceIndex][line];
11687
+ if (segments == null)
11688
+ return all ? [] : GMapping(null, null);
11689
+ const memo = map._bySourceMemos[sourceIndex];
11690
+ if (all)
11691
+ return sliceGeneratedPositions(segments, memo, line, column, bias);
11692
+ const index = traceSegmentInternal(segments, memo, line, column, bias);
11693
+ if (index === -1)
11694
+ return GMapping(null, null);
11695
+ const segment = segments[index];
11696
+ return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]);
11697
+ }
11698
+ })();
11699
+ function GMapping(line, column) {
11700
+ return { line, column };
12409
11701
  }
12410
-
12411
- // Matches the scheme of a URL, eg "http://"
12412
- const schemeRegex = /^[\w+.-]+:\/\//;
12413
- /**
12414
- * Matches the parts of a URL:
12415
- * 1. Scheme, including ":", guaranteed.
12416
- * 2. User/password, including "@", optional.
12417
- * 3. Host, guaranteed.
12418
- * 4. Port, including ":", optional.
12419
- * 5. Path, including "/", optional.
12420
- * 6. Query, including "?", optional.
12421
- * 7. Hash, including "#", optional.
12422
- */
12423
- const urlRegex = /^([\w+.-]+:)\/\/([^@/#?]*@)?([^:/#?]*)(:\d+)?(\/[^#?]*)?(\?[^#]*)?(#.*)?/;
12424
- /**
12425
- * File URLs are weird. They dont' need the regular `//` in the scheme, they may or may not start
12426
- * with a leading `/`, they can have a domain (but only if they don't start with a Windows drive).
12427
- *
12428
- * 1. Host, optional.
12429
- * 2. Path, which may include "/", guaranteed.
12430
- * 3. Query, including "?", optional.
12431
- * 4. Hash, including "#", optional.
12432
- */
12433
- const fileRegex = /^file:(?:\/\/((?![a-z]:)[^/#?]*)?)?(\/?[^#?]*)(\?[^#]*)?(#.*)?/i;
12434
- var UrlType;
12435
- (function (UrlType) {
12436
- UrlType[UrlType["Empty"] = 1] = "Empty";
12437
- UrlType[UrlType["Hash"] = 2] = "Hash";
12438
- UrlType[UrlType["Query"] = 3] = "Query";
12439
- UrlType[UrlType["RelativePath"] = 4] = "RelativePath";
12440
- UrlType[UrlType["AbsolutePath"] = 5] = "AbsolutePath";
12441
- UrlType[UrlType["SchemeRelative"] = 6] = "SchemeRelative";
12442
- UrlType[UrlType["Absolute"] = 7] = "Absolute";
12443
- })(UrlType || (UrlType = {}));
12444
- function isAbsoluteUrl(input) {
12445
- return schemeRegex.test(input);
11702
+ function traceSegmentInternal(segments, memo, line, column, bias) {
11703
+ let index = memoizedBinarySearch(segments, column, memo, line);
11704
+ if (found) {
11705
+ index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
11706
+ }
11707
+ else if (bias === LEAST_UPPER_BOUND)
11708
+ index++;
11709
+ if (index === -1 || index === segments.length)
11710
+ return -1;
11711
+ return index;
12446
11712
  }
12447
- function isSchemeRelativeUrl(input) {
12448
- return input.startsWith('//');
11713
+ function sliceGeneratedPositions(segments, memo, line, column, bias) {
11714
+ let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND);
11715
+ // We ignored the bias when tracing the segment so that we're guarnateed to find the first (in
11716
+ // insertion order) segment that matched. Even if we did respect the bias when tracing, we would
11717
+ // still need to call `lowerBound()` to find the first segment, which is slower than just looking
11718
+ // for the GREATEST_LOWER_BOUND to begin with. The only difference that matters for us is when the
11719
+ // binary search didn't match, in which case GREATEST_LOWER_BOUND just needs to increment to
11720
+ // match LEAST_UPPER_BOUND.
11721
+ if (!found && bias === LEAST_UPPER_BOUND)
11722
+ min++;
11723
+ if (min === -1 || min === segments.length)
11724
+ return [];
11725
+ // We may have found the segment that started at an earlier column. If this is the case, then we
11726
+ // need to slice all generated segments that match _that_ column, because all such segments span
11727
+ // to our desired column.
11728
+ const matchedColumn = found ? column : segments[min][COLUMN];
11729
+ // The binary search is not guaranteed to find the lower bound when a match wasn't found.
11730
+ if (!found)
11731
+ min = lowerBound(segments, matchedColumn, min);
11732
+ const max = upperBound(segments, matchedColumn, min);
11733
+ const result = [];
11734
+ for (; min <= max; min++) {
11735
+ const segment = segments[min];
11736
+ result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]));
11737
+ }
11738
+ return result;
12449
11739
  }
12450
- function isAbsolutePath(input) {
12451
- return input.startsWith('/');
11740
+
11741
+ function L(n){return /^\\\\\?\\/.test(n)?n:n.replace(/\\/g,"/")}function S(n,s){for(;;){const t=p.posix.join(n,s);if(require$$0$3.existsSync(t))return t;const e=p.dirname(n);if(e===n)return;n=e;}}const W=/^\.{1,2}(\/.*)?$/,M=n=>L(W.test(n)?n:`./${n}`);function un(n,s=!1){const t=n.length;let e=0,i="",l=0,c=16,a=0,g=0,v=0,k=0,r=0;function F(o,f){let u=0,j=0;for(;u<o||!f;){let T=n.charCodeAt(e);if(T>=48&&T<=57)j=j*16+T-48;else if(T>=65&&T<=70)j=j*16+T-65+10;else if(T>=97&&T<=102)j=j*16+T-97+10;else break;e++,u++;}return u<o&&(j=-1),j}function U(o){e=o,i="",l=0,c=16,r=0;}function A(){let o=e;if(n.charCodeAt(e)===48)e++;else for(e++;e<n.length&&_(n.charCodeAt(e));)e++;if(e<n.length&&n.charCodeAt(e)===46)if(e++,e<n.length&&_(n.charCodeAt(e)))for(e++;e<n.length&&_(n.charCodeAt(e));)e++;else return r=3,n.substring(o,e);let f=e;if(e<n.length&&(n.charCodeAt(e)===69||n.charCodeAt(e)===101))if(e++,(e<n.length&&n.charCodeAt(e)===43||n.charCodeAt(e)===45)&&e++,e<n.length&&_(n.charCodeAt(e))){for(e++;e<n.length&&_(n.charCodeAt(e));)e++;f=e;}else r=3;return n.substring(o,f)}function b(){let o="",f=e;for(;;){if(e>=t){o+=n.substring(f,e),r=2;break}const u=n.charCodeAt(e);if(u===34){o+=n.substring(f,e),e++;break}if(u===92){if(o+=n.substring(f,e),e++,e>=t){r=2;break}switch(n.charCodeAt(e++)){case 34:o+='"';break;case 92:o+="\\";break;case 47:o+="/";break;case 98:o+="\b";break;case 102:o+="\f";break;case 110:o+=`
11742
+ `;break;case 114:o+="\r";break;case 116:o+=" ";break;case 117:const T=F(4,!0);T>=0?o+=String.fromCharCode(T):r=4;break;default:r=5;}f=e;continue}if(u>=0&&u<=31)if(N(u)){o+=n.substring(f,e),r=2;break}else r=6;e++;}return o}function O(){if(i="",r=0,l=e,g=a,k=v,e>=t)return l=t,c=17;let o=n.charCodeAt(e);if(R(o)){do e++,i+=String.fromCharCode(o),o=n.charCodeAt(e);while(R(o));return c=15}if(N(o))return e++,i+=String.fromCharCode(o),o===13&&n.charCodeAt(e)===10&&(e++,i+=`
11743
+ `),a++,v=e,c=14;switch(o){case 123:return e++,c=1;case 125:return e++,c=2;case 91:return e++,c=3;case 93:return e++,c=4;case 58:return e++,c=6;case 44:return e++,c=5;case 34:return e++,i=b(),c=10;case 47:const f=e-1;if(n.charCodeAt(e+1)===47){for(e+=2;e<t&&!N(n.charCodeAt(e));)e++;return i=n.substring(f,e),c=12}if(n.charCodeAt(e+1)===42){e+=2;const u=t-1;let j=!1;for(;e<u;){const T=n.charCodeAt(e);if(T===42&&n.charCodeAt(e+1)===47){e+=2,j=!0;break}e++,N(T)&&(T===13&&n.charCodeAt(e)===10&&e++,a++,v=e);}return j||(e++,r=1),i=n.substring(f,e),c=13}return i+=String.fromCharCode(o),e++,c=16;case 45:if(i+=String.fromCharCode(o),e++,e===t||!_(n.charCodeAt(e)))return c=16;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return i+=A(),c=11;default:for(;e<t&&E(o);)e++,o=n.charCodeAt(e);if(l!==e){switch(i=n.substring(l,e),i){case"true":return c=8;case"false":return c=9;case"null":return c=7}return c=16}return i+=String.fromCharCode(o),e++,c=16}}function E(o){if(R(o)||N(o))return !1;switch(o){case 125:case 93:case 123:case 91:case 34:case 58:case 44:case 47:return !1}return !0}function $(){let o;do o=O();while(o>=12&&o<=15);return o}return {setPosition:U,getPosition:()=>e,scan:s?$:O,getToken:()=>c,getTokenValue:()=>i,getTokenOffset:()=>l,getTokenLength:()=>e-l,getTokenStartLine:()=>g,getTokenStartCharacter:()=>l-k,getTokenError:()=>r}}function R(n){return n===32||n===9}function N(n){return n===10||n===13}function _(n){return n>=48&&n<=57}var P;(function(n){n[n.lineFeed=10]="lineFeed",n[n.carriageReturn=13]="carriageReturn",n[n.space=32]="space",n[n._0=48]="_0",n[n._1=49]="_1",n[n._2=50]="_2",n[n._3=51]="_3",n[n._4=52]="_4",n[n._5=53]="_5",n[n._6=54]="_6",n[n._7=55]="_7",n[n._8=56]="_8",n[n._9=57]="_9",n[n.a=97]="a",n[n.b=98]="b",n[n.c=99]="c",n[n.d=100]="d",n[n.e=101]="e",n[n.f=102]="f",n[n.g=103]="g",n[n.h=104]="h",n[n.i=105]="i",n[n.j=106]="j",n[n.k=107]="k",n[n.l=108]="l",n[n.m=109]="m",n[n.n=110]="n",n[n.o=111]="o",n[n.p=112]="p",n[n.q=113]="q",n[n.r=114]="r",n[n.s=115]="s",n[n.t=116]="t",n[n.u=117]="u",n[n.v=118]="v",n[n.w=119]="w",n[n.x=120]="x",n[n.y=121]="y",n[n.z=122]="z",n[n.A=65]="A",n[n.B=66]="B",n[n.C=67]="C",n[n.D=68]="D",n[n.E=69]="E",n[n.F=70]="F",n[n.G=71]="G",n[n.H=72]="H",n[n.I=73]="I",n[n.J=74]="J",n[n.K=75]="K",n[n.L=76]="L",n[n.M=77]="M",n[n.N=78]="N",n[n.O=79]="O",n[n.P=80]="P",n[n.Q=81]="Q",n[n.R=82]="R",n[n.S=83]="S",n[n.T=84]="T",n[n.U=85]="U",n[n.V=86]="V",n[n.W=87]="W",n[n.X=88]="X",n[n.Y=89]="Y",n[n.Z=90]="Z",n[n.asterisk=42]="asterisk",n[n.backslash=92]="backslash",n[n.closeBrace=125]="closeBrace",n[n.closeBracket=93]="closeBracket",n[n.colon=58]="colon",n[n.comma=44]="comma",n[n.dot=46]="dot",n[n.doubleQuote=34]="doubleQuote",n[n.minus=45]="minus",n[n.openBrace=123]="openBrace",n[n.openBracket=91]="openBracket",n[n.plus=43]="plus",n[n.slash=47]="slash",n[n.formFeed=12]="formFeed",n[n.tab=9]="tab";})(P||(P={}));var h;(function(n){n.DEFAULT={allowTrailingComma:!1};})(h||(h={}));function fn(n,s=[],t=h.DEFAULT){let e=null,i=[];const l=[];function c(g){Array.isArray(i)?i.push(g):e!==null&&(i[e]=g);}return rn(n,{onObjectBegin:()=>{const g={};c(g),l.push(i),i=g,e=null;},onObjectProperty:g=>{e=g;},onObjectEnd:()=>{i=l.pop();},onArrayBegin:()=>{const g=[];c(g),l.push(i),i=g,e=null;},onArrayEnd:()=>{i=l.pop();},onLiteralValue:c,onError:(g,v,k)=>{s.push({error:g,offset:v,length:k});}},t),i[0]}function rn(n,s,t=h.DEFAULT){const e=un(n,!1),i=[];function l(m){return m?()=>m(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter()):()=>!0}function c(m){return m?()=>m(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter(),()=>i.slice()):()=>!0}function a(m){return m?w=>m(w,e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter()):()=>!0}function g(m){return m?w=>m(w,e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter(),()=>i.slice()):()=>!0}const v=c(s.onObjectBegin),k=g(s.onObjectProperty),r=l(s.onObjectEnd),F=c(s.onArrayBegin),U=l(s.onArrayEnd),A=g(s.onLiteralValue),b=a(s.onSeparator),O=l(s.onComment),E=a(s.onError),$=t&&t.disallowComments,o=t&&t.allowTrailingComma;function f(){for(;;){const m=e.scan();switch(e.getTokenError()){case 4:u(14);break;case 5:u(15);break;case 3:u(13);break;case 1:$||u(11);break;case 2:u(12);break;case 6:u(16);break}switch(m){case 12:case 13:$?u(10):O();break;case 16:u(1);break;case 15:case 14:break;default:return m}}}function u(m,w=[],H=[]){if(E(m),w.length+H.length>0){let I=e.getToken();for(;I!==17;){if(w.indexOf(I)!==-1){f();break}else if(H.indexOf(I)!==-1)break;I=f();}}}function j(m){const w=e.getTokenValue();return m?A(w):(k(w),i.push(w)),f(),!0}function T(){switch(e.getToken()){case 11:const m=e.getTokenValue();let w=Number(m);isNaN(w)&&(u(2),w=0),A(w);break;case 7:A(null);break;case 8:A(!0);break;case 9:A(!1);break;default:return !1}return f(),!0}function sn(){return e.getToken()!==10?(u(3,[],[2,5]),!1):(j(!1),e.getToken()===6?(b(":"),f(),V()||u(4,[],[2,5])):u(5,[],[2,5]),i.pop(),!0)}function on(){v(),f();let m=!1;for(;e.getToken()!==2&&e.getToken()!==17;){if(e.getToken()===5){if(m||u(4,[],[]),b(","),f(),e.getToken()===2&&o)break}else m&&u(6,[],[]);sn()||u(4,[],[2,5]),m=!0;}return r(),e.getToken()!==2?u(7,[2],[]):f(),!0}function ln(){F(),f();let m=!0,w=!1;for(;e.getToken()!==4&&e.getToken()!==17;){if(e.getToken()===5){if(w||u(4,[],[]),b(","),f(),e.getToken()===4&&o)break}else w&&u(6,[],[]);m?(i.push(0),m=!1):i[i.length-1]++,V()||u(4,[],[4,5]),w=!0;}return U(),m||i.pop(),e.getToken()!==4?u(8,[4],[]):f(),!0}function V(){switch(e.getToken()){case 3:return ln();case 1:return on();case 10:return j(!0);default:return T()}}return f(),e.getToken()===17?t.allowEmptyContent?!0:(u(4,[],[]),!1):V()?(e.getToken()!==17&&u(9,[],[]),!0):(u(4,[],[]),!1)}var X;(function(n){n[n.None=0]="None",n[n.UnexpectedEndOfComment=1]="UnexpectedEndOfComment",n[n.UnexpectedEndOfString=2]="UnexpectedEndOfString",n[n.UnexpectedEndOfNumber=3]="UnexpectedEndOfNumber",n[n.InvalidUnicode=4]="InvalidUnicode",n[n.InvalidEscapeCharacter=5]="InvalidEscapeCharacter",n[n.InvalidCharacter=6]="InvalidCharacter";})(X||(X={}));var Y;(function(n){n[n.OpenBraceToken=1]="OpenBraceToken",n[n.CloseBraceToken=2]="CloseBraceToken",n[n.OpenBracketToken=3]="OpenBracketToken",n[n.CloseBracketToken=4]="CloseBracketToken",n[n.CommaToken=5]="CommaToken",n[n.ColonToken=6]="ColonToken",n[n.NullKeyword=7]="NullKeyword",n[n.TrueKeyword=8]="TrueKeyword",n[n.FalseKeyword=9]="FalseKeyword",n[n.StringLiteral=10]="StringLiteral",n[n.NumericLiteral=11]="NumericLiteral",n[n.LineCommentTrivia=12]="LineCommentTrivia",n[n.BlockCommentTrivia=13]="BlockCommentTrivia",n[n.LineBreakTrivia=14]="LineBreakTrivia",n[n.Trivia=15]="Trivia",n[n.Unknown=16]="Unknown",n[n.EOF=17]="EOF";})(Y||(Y={}));const pn=fn;var Z;(function(n){n[n.InvalidSymbol=1]="InvalidSymbol",n[n.InvalidNumberFormat=2]="InvalidNumberFormat",n[n.PropertyNameExpected=3]="PropertyNameExpected",n[n.ValueExpected=4]="ValueExpected",n[n.ColonExpected=5]="ColonExpected",n[n.CommaExpected=6]="CommaExpected",n[n.CloseBraceExpected=7]="CloseBraceExpected",n[n.CloseBracketExpected=8]="CloseBracketExpected",n[n.EndOfFileExpected=9]="EndOfFileExpected",n[n.InvalidCommentToken=10]="InvalidCommentToken",n[n.UnexpectedEndOfComment=11]="UnexpectedEndOfComment",n[n.UnexpectedEndOfString=12]="UnexpectedEndOfString",n[n.UnexpectedEndOfNumber=13]="UnexpectedEndOfNumber",n[n.InvalidUnicode=14]="InvalidUnicode",n[n.InvalidEscapeCharacter=15]="InvalidEscapeCharacter",n[n.InvalidCharacter=16]="InvalidCharacter";})(Z||(Z={}));const q=n=>pn(require$$0$3.readFileSync(n,"utf8")),{existsSync:D}=require$$0$3,gn=()=>{const{findPnpApi:n}=cn;return n&&n(process.cwd())};function d(n){const s=q(n);return p.join(n,"..",s&&"tsconfig"in s?s.tsconfig:"tsconfig.json")}function mn(n,s){let t=n;const e=n[0]===".";if(e||p.isAbsolute(n)){if(e&&(t===".."&&(t+="/tsconfig.json"),t=p.resolve(s,t)),D(t)&&require$$0$3.statSync(t).isFile()||!t.endsWith(".json")&&(t+=".json",D(t)))return t;throw new Error(`File '${n}' not found.`)}const i=gn();if(i){const{resolveRequest:c}=i,[a,g]=n.split("/"),v=a.startsWith("@")?`${a}/${g}`:a;try{if(v===n){const k=c(p.join(v,"package.json"),s);if(k){const r=d(k);if(D(r))return r}}else {let k;try{k=c(n,s,{extensions:[".json"]});}catch{k=c(p.join(n,"tsconfig.json"),s);}if(k)return k}}catch{}}let l=S(s,p.join("node_modules",t));if(l){if(require$$0$3.statSync(l).isDirectory()){const c=p.join(l,"package.json");if(D(c)?l=d(c):l=p.join(l,"tsconfig.json"),D(l))return l}else if(l.endsWith(".json"))return l}if(!t.endsWith(".json")&&(t+=".json",l=S(s,p.join("node_modules",t)),l))return l;throw new Error(`File '${n}' not found.`)}const an=(n,s)=>{var t;const e=mn(n,s),i=J(e);if(delete i.references,(t=i.compilerOptions)!=null&&t.baseUrl){const{compilerOptions:l}=i;l.baseUrl=p.relative(s,p.join(p.dirname(e),l.baseUrl))||"./";}return i.files&&(i.files=i.files.map(l=>p.relative(s,p.join(p.dirname(e),l)))),i.include&&(i.include=i.include.map(l=>p.relative(s,p.join(p.dirname(e),l)))),i},J=n=>{let s;try{s=require$$0$3.realpathSync(n);}catch{throw new Error(`Cannot resolve tsconfig at path: ${n}`)}const t=p.dirname(s);let e=q(s)||{};if(typeof e!="object")throw new SyntaxError(`Failed to parse tsconfig at: ${n}`);if(e.extends){const i=Array.isArray(e.extends)?e.extends:[e.extends];delete e.extends;for(const l of i.reverse()){const c=an(l,t),a={...c,...e,compilerOptions:{...c.compilerOptions,...e.compilerOptions}};c.watchOptions&&(a.watchOptions={...c.watchOptions,...e.watchOptions}),e=a;}}if(e.compilerOptions){const{compilerOptions:i}=e;i.baseUrl&&(i.baseUrl=M(i.baseUrl)),i.outDir&&(Array.isArray(e.exclude)||(e.exclude=[]),e.exclude.push(i.outDir),i.outDir=M(i.outDir));}else e.compilerOptions={};if(e.files&&(e.files=e.files.map(M)),e.include&&(e.include=e.include.map(L)),e.watchOptions){const{watchOptions:i}=e;i.excludeDirectories&&(i.excludeDirectories=i.excludeDirectories.map(l=>L(p.resolve(t,l))));}return e};function kn(n=process.cwd(),s="tsconfig.json"){const t=S(L(n),s);if(!t)return null;const e=J(t);return {path:t,config:e}}p.posix;process.platform==="win32";
11744
+
11745
+ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
11746
+ const newLineRegExp = /\r?\n/;
11747
+ const errCodeRegExp = /error TS(?<errCode>\d+)/;
11748
+ async function makeTscErrorInfo(errInfo) {
11749
+ var _a;
11750
+ const [errFilePathPos = "", ...errMsgRawArr] = errInfo.split(":");
11751
+ if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0)
11752
+ return ["unknown filepath", null];
11753
+ const errMsgRaw = errMsgRawArr.join("").trim();
11754
+ const [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
11755
+ if (!errFilePath || !errPos)
11756
+ return ["unknown filepath", null];
11757
+ const [errLine, errCol] = errPos.split(",");
11758
+ if (!errLine || !errCol)
11759
+ return [errFilePath, null];
11760
+ const execArr = errCodeRegExp.exec(errMsgRaw);
11761
+ if (!execArr)
11762
+ return [errFilePath, null];
11763
+ const errCodeStr = ((_a = execArr.groups) == null ? void 0 : _a.errCode) ?? "";
11764
+ if (!errCodeStr)
11765
+ return [errFilePath, null];
11766
+ const line = Number(errLine);
11767
+ const col = Number(errCol);
11768
+ const errCode = Number(errCodeStr);
11769
+ return [
11770
+ errFilePath,
11771
+ {
11772
+ filePath: errFilePath,
11773
+ errCode,
11774
+ line,
11775
+ column: col,
11776
+ errMsg: errMsgRaw.slice(`error TS${errCode} `.length)
11777
+ }
11778
+ ];
12452
11779
  }
12453
- function isFileUrl(input) {
12454
- return input.startsWith('file:');
11780
+ async function getTsconfig(root, config) {
11781
+ var _a;
11782
+ const configName = ((_a = config.tsconfig) == null ? void 0 : _a.includes("jsconfig.json")) ? "jsconfig.json" : void 0;
11783
+ const tsconfig = kn(config.tsconfig || root, configName);
11784
+ if (!tsconfig)
11785
+ throw new Error("no tsconfig.json found");
11786
+ const tempConfigPath = join(dirname(tsconfig.path), "tsconfig.vitest-temp.json");
11787
+ try {
11788
+ const tmpTsConfig = { ...tsconfig.config };
11789
+ tmpTsConfig.compilerOptions = tmpTsConfig.compilerOptions || {};
11790
+ tmpTsConfig.compilerOptions.emitDeclarationOnly = false;
11791
+ tmpTsConfig.compilerOptions.incremental = true;
11792
+ tmpTsConfig.compilerOptions.tsBuildInfoFile = join(
11793
+ __dirname,
11794
+ "tsconfig.tmp.tsbuildinfo"
11795
+ );
11796
+ const tsconfigFinalContent = JSON.stringify(tmpTsConfig, null, 2);
11797
+ await writeFile(tempConfigPath, tsconfigFinalContent);
11798
+ return { path: tempConfigPath, config: tmpTsConfig };
11799
+ } catch (err) {
11800
+ throw new Error("failed to write tsconfig.temp.json", { cause: err });
11801
+ }
12455
11802
  }
12456
- function isRelative(input) {
12457
- return /^[.?#]/.test(input);
11803
+ async function getRawErrsMapFromTsCompile(tscErrorStdout) {
11804
+ const rawErrsMap = /* @__PURE__ */ new Map();
11805
+ const infos = await Promise.all(
11806
+ tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
11807
+ if (!next)
11808
+ return prev;
11809
+ else if (!next.startsWith(" "))
11810
+ prev.push(next);
11811
+ else
11812
+ prev[prev.length - 1] += `
11813
+ ${next}`;
11814
+ return prev;
11815
+ }, []).map((errInfoLine) => makeTscErrorInfo(errInfoLine))
11816
+ );
11817
+ infos.forEach(([errFilePath, errInfo]) => {
11818
+ var _a;
11819
+ if (!errInfo)
11820
+ return;
11821
+ if (!rawErrsMap.has(errFilePath))
11822
+ rawErrsMap.set(errFilePath, [errInfo]);
11823
+ else
11824
+ (_a = rawErrsMap.get(errFilePath)) == null ? void 0 : _a.push(errInfo);
11825
+ });
11826
+ return rawErrsMap;
12458
11827
  }
12459
- function parseAbsoluteUrl(input) {
12460
- const match = urlRegex.exec(input);
12461
- return makeUrl(match[1], match[2] || '', match[3], match[4] || '', match[5] || '/', match[6] || '', match[7] || '');
11828
+
11829
+ function createIndexMap(source) {
11830
+ const map = /* @__PURE__ */ new Map();
11831
+ let index = 0;
11832
+ let line = 1;
11833
+ let column = 1;
11834
+ for (const char of source) {
11835
+ map.set(`${line}:${column}`, index++);
11836
+ if (char === "\n" || char === "\r\n") {
11837
+ line++;
11838
+ column = 0;
11839
+ } else {
11840
+ column++;
11841
+ }
11842
+ }
11843
+ return map;
11844
+ }
11845
+
11846
+ async function collectTests(ctx, filepath) {
11847
+ const request = await ctx.vitenode.transformRequest(filepath, filepath);
11848
+ if (!request)
11849
+ return null;
11850
+ const ast = parse$4(request.code, {
11851
+ ecmaVersion: "latest",
11852
+ allowAwaitOutsideFunction: true
11853
+ });
11854
+ const testFilepath = relative(ctx.config.root, filepath);
11855
+ const file = {
11856
+ filepath,
11857
+ type: "suite",
11858
+ id: generateHash(`${testFilepath}${ctx.config.name || ""}`),
11859
+ name: testFilepath,
11860
+ mode: "run",
11861
+ tasks: [],
11862
+ start: ast.start,
11863
+ end: ast.end,
11864
+ meta: { typecheck: true }
11865
+ };
11866
+ const definitions = [];
11867
+ const getName = (callee) => {
11868
+ var _a, _b, _c;
11869
+ if (!callee)
11870
+ return null;
11871
+ if (callee.type === "Identifier")
11872
+ return callee.name;
11873
+ if (callee.type === "MemberExpression") {
11874
+ if ((_b = (_a = callee.object) == null ? void 0 : _a.name) == null ? void 0 : _b.startsWith("__vite_ssr_"))
11875
+ return getName(callee.property);
11876
+ return getName((_c = callee.object) == null ? void 0 : _c.property);
11877
+ }
11878
+ return null;
11879
+ };
11880
+ ancestor(ast, {
11881
+ CallExpression(node) {
11882
+ var _a;
11883
+ const { callee } = node;
11884
+ const name = getName(callee);
11885
+ if (!name)
11886
+ return;
11887
+ if (!["it", "test", "describe", "suite"].includes(name))
11888
+ return;
11889
+ const { arguments: [{ value: message }] } = node;
11890
+ const property = (_a = callee == null ? void 0 : callee.property) == null ? void 0 : _a.name;
11891
+ let mode = !property || property === name ? "run" : property;
11892
+ if (!["run", "skip", "todo", "only", "skipIf", "runIf"].includes(mode))
11893
+ throw new Error(`${name}.${mode} syntax is not supported when testing types`);
11894
+ if (mode === "skipIf" || mode === "runIf")
11895
+ mode = "skip";
11896
+ definitions.push({
11897
+ start: node.start,
11898
+ end: node.end,
11899
+ name: message,
11900
+ type: name === "it" || name === "test" ? "test" : "suite",
11901
+ mode
11902
+ });
11903
+ }
11904
+ });
11905
+ let lastSuite = file;
11906
+ const updateLatestSuite = (index) => {
11907
+ const suite = lastSuite;
11908
+ while (lastSuite !== file && lastSuite.end < index)
11909
+ lastSuite = suite.suite;
11910
+ return lastSuite;
11911
+ };
11912
+ definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
11913
+ const latestSuite = updateLatestSuite(definition.start);
11914
+ let mode = definition.mode;
11915
+ if (latestSuite.mode !== "run")
11916
+ mode = latestSuite.mode;
11917
+ if (definition.type === "suite") {
11918
+ const task2 = {
11919
+ type: definition.type,
11920
+ id: "",
11921
+ suite: latestSuite,
11922
+ file,
11923
+ tasks: [],
11924
+ mode,
11925
+ name: definition.name,
11926
+ end: definition.end,
11927
+ start: definition.start,
11928
+ meta: {
11929
+ typecheck: true
11930
+ }
11931
+ };
11932
+ definition.task = task2;
11933
+ latestSuite.tasks.push(task2);
11934
+ lastSuite = task2;
11935
+ return;
11936
+ }
11937
+ const task = {
11938
+ type: definition.type,
11939
+ id: "",
11940
+ suite: latestSuite,
11941
+ file,
11942
+ mode,
11943
+ context: {},
11944
+ // not used in typecheck
11945
+ name: definition.name,
11946
+ end: definition.end,
11947
+ start: definition.start,
11948
+ meta: {
11949
+ typecheck: true
11950
+ }
11951
+ };
11952
+ definition.task = task;
11953
+ latestSuite.tasks.push(task);
11954
+ });
11955
+ calculateSuiteHash(file);
11956
+ const hasOnly = someTasksAreOnly(file);
11957
+ interpretTaskModes(file, ctx.config.testNamePattern, hasOnly, false, ctx.config.allowOnly);
11958
+ return {
11959
+ file,
11960
+ parsed: request.code,
11961
+ filepath,
11962
+ map: request.map,
11963
+ definitions
11964
+ };
12462
11965
  }
12463
- function parseFileUrl(input) {
12464
- const match = fileRegex.exec(input);
12465
- const path = match[2];
12466
- return makeUrl('file:', '', match[1] || '', '', isAbsolutePath(path) ? path : '/' + path, match[3] || '', match[4] || '');
11966
+
11967
+ class TypeCheckError extends Error {
11968
+ constructor(message, stacks) {
11969
+ super(message);
11970
+ this.message = message;
11971
+ this.stacks = stacks;
11972
+ this.name = "TypeCheckError";
11973
+ }
12467
11974
  }
12468
- function makeUrl(scheme, user, host, port, path, query, hash) {
12469
- return {
12470
- scheme,
12471
- user,
12472
- host,
12473
- port,
12474
- path,
12475
- query,
12476
- hash,
12477
- type: UrlType.Absolute,
11975
+ class Typechecker {
11976
+ constructor(ctx, files) {
11977
+ this.ctx = ctx;
11978
+ this.files = files;
11979
+ this._result = {
11980
+ files: [],
11981
+ sourceErrors: []
12478
11982
  };
12479
- }
12480
- function parseUrl(input) {
12481
- if (isSchemeRelativeUrl(input)) {
12482
- const url = parseAbsoluteUrl('http:' + input);
12483
- url.scheme = '';
12484
- url.type = UrlType.SchemeRelative;
12485
- return url;
11983
+ this._tests = {};
11984
+ }
11985
+ onParseStart(fn) {
11986
+ this._onParseStart = fn;
11987
+ }
11988
+ onParseEnd(fn) {
11989
+ this._onParseEnd = fn;
11990
+ }
11991
+ onWatcherRerun(fn) {
11992
+ this._onWatcherRerun = fn;
11993
+ }
11994
+ async collectFileTests(filepath) {
11995
+ return collectTests(this.ctx, filepath);
11996
+ }
11997
+ getFiles() {
11998
+ return this.files.filter((filename) => {
11999
+ const extension = extname(filename);
12000
+ return extension !== ".js" || this.allowJs;
12001
+ });
12002
+ }
12003
+ async collectTests() {
12004
+ const tests = (await Promise.all(
12005
+ this.getFiles().map((filepath) => this.collectFileTests(filepath))
12006
+ )).reduce((acc, data) => {
12007
+ if (!data)
12008
+ return acc;
12009
+ acc[data.filepath] = data;
12010
+ return acc;
12011
+ }, {});
12012
+ this._tests = tests;
12013
+ return tests;
12014
+ }
12015
+ markPassed(file) {
12016
+ var _a;
12017
+ if (!((_a = file.result) == null ? void 0 : _a.state)) {
12018
+ file.result = {
12019
+ state: "pass"
12020
+ };
12486
12021
  }
12487
- if (isAbsolutePath(input)) {
12488
- const url = parseAbsoluteUrl('http://foo.com' + input);
12489
- url.scheme = '';
12490
- url.host = '';
12491
- url.type = UrlType.AbsolutePath;
12492
- return url;
12022
+ const markTasks = (tasks) => {
12023
+ var _a2;
12024
+ for (const task of tasks) {
12025
+ if ("tasks" in task)
12026
+ markTasks(task.tasks);
12027
+ if (!((_a2 = task.result) == null ? void 0 : _a2.state) && task.mode === "run") {
12028
+ task.result = {
12029
+ state: "pass"
12030
+ };
12031
+ }
12032
+ }
12033
+ };
12034
+ markTasks(file.tasks);
12035
+ }
12036
+ async prepareResults(output) {
12037
+ const typeErrors = await this.parseTscLikeOutput(output);
12038
+ const testFiles = new Set(this.getFiles());
12039
+ if (!this._tests)
12040
+ this._tests = await this.collectTests();
12041
+ const sourceErrors = [];
12042
+ const files = [];
12043
+ testFiles.forEach((path) => {
12044
+ const { file, definitions, map, parsed } = this._tests[path];
12045
+ const errors = typeErrors.get(path);
12046
+ files.push(file);
12047
+ if (!errors) {
12048
+ this.markPassed(file);
12049
+ return;
12050
+ }
12051
+ const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)];
12052
+ const traceMap = map && new TraceMap(map);
12053
+ const indexMap = createIndexMap(parsed);
12054
+ const markState = (task, state) => {
12055
+ task.result = {
12056
+ state: task.mode === "run" || task.mode === "only" ? state : task.mode
12057
+ };
12058
+ if (task.suite)
12059
+ markState(task.suite, state);
12060
+ };
12061
+ errors.forEach(({ error, originalError }) => {
12062
+ var _a;
12063
+ const processedPos = traceMap ? generatedPositionFor(traceMap, {
12064
+ line: originalError.line,
12065
+ column: originalError.column,
12066
+ source: basename(path)
12067
+ }) : originalError;
12068
+ const line = processedPos.line ?? originalError.line;
12069
+ const column = processedPos.column ?? originalError.column;
12070
+ const index = indexMap.get(`${line}:${column}`);
12071
+ const definition = index != null && sortedDefinitions.find((def) => def.start <= index && def.end >= index);
12072
+ const suite = definition ? definition.task : file;
12073
+ const state = suite.mode === "run" || suite.mode === "only" ? "fail" : suite.mode;
12074
+ const errors2 = ((_a = suite.result) == null ? void 0 : _a.errors) || [];
12075
+ suite.result = {
12076
+ state,
12077
+ errors: errors2
12078
+ };
12079
+ errors2.push(error);
12080
+ if (state === "fail" && suite.suite)
12081
+ markState(suite.suite, "fail");
12082
+ });
12083
+ this.markPassed(file);
12084
+ });
12085
+ typeErrors.forEach((errors, path) => {
12086
+ if (!testFiles.has(path))
12087
+ sourceErrors.push(...errors.map(({ error }) => error));
12088
+ });
12089
+ return {
12090
+ files,
12091
+ sourceErrors
12092
+ };
12093
+ }
12094
+ async parseTscLikeOutput(output) {
12095
+ const errorsMap = await getRawErrsMapFromTsCompile(output);
12096
+ const typesErrors = /* @__PURE__ */ new Map();
12097
+ errorsMap.forEach((errors, path) => {
12098
+ const filepath = resolve$2(this.ctx.config.root, path);
12099
+ const suiteErrors = errors.map((info) => {
12100
+ const limit = Error.stackTraceLimit;
12101
+ Error.stackTraceLimit = 0;
12102
+ const error = new TypeCheckError(info.errMsg, [
12103
+ {
12104
+ file: filepath,
12105
+ line: info.line,
12106
+ column: info.column,
12107
+ method: ""
12108
+ }
12109
+ ]);
12110
+ Error.stackTraceLimit = limit;
12111
+ return {
12112
+ originalError: info,
12113
+ error
12114
+ };
12115
+ });
12116
+ typesErrors.set(filepath, suiteErrors);
12117
+ });
12118
+ return typesErrors;
12119
+ }
12120
+ async clear() {
12121
+ if (this.tempConfigPath)
12122
+ await rm(this.tempConfigPath, { force: true });
12123
+ }
12124
+ async stop() {
12125
+ var _a;
12126
+ await this.clear();
12127
+ (_a = this.process) == null ? void 0 : _a.kill();
12128
+ }
12129
+ async ensurePackageInstalled(root, checker) {
12130
+ if (checker !== "tsc" && checker !== "vue-tsc")
12131
+ return;
12132
+ const packageName = checker === "tsc" ? "typescript" : "vue-tsc";
12133
+ await ensurePackageInstalled(packageName, root);
12134
+ }
12135
+ async prepare() {
12136
+ const { root, typecheck } = this.ctx.config;
12137
+ await this.ensurePackageInstalled(root, typecheck.checker);
12138
+ const { config, path } = await getTsconfig(root, typecheck);
12139
+ this.tempConfigPath = path;
12140
+ this.allowJs = typecheck.allowJs || config.allowJs || false;
12141
+ }
12142
+ async start() {
12143
+ var _a, _b, _c;
12144
+ if (!this.tempConfigPath)
12145
+ throw new Error("tsconfig was not initialized");
12146
+ const { root, watch, typecheck } = this.ctx.config;
12147
+ const args = ["--noEmit", "--pretty", "false", "-p", this.tempConfigPath];
12148
+ if (watch)
12149
+ args.push("--watch");
12150
+ if (typecheck.allowJs)
12151
+ args.push("--allowJs", "--checkJs");
12152
+ let output = "";
12153
+ const child = execa(typecheck.checker, args, {
12154
+ cwd: root,
12155
+ stdout: "pipe",
12156
+ reject: false
12157
+ });
12158
+ this.process = child;
12159
+ await ((_a = this._onParseStart) == null ? void 0 : _a.call(this));
12160
+ let rerunTriggered = false;
12161
+ (_b = child.stdout) == null ? void 0 : _b.on("data", (chunk) => {
12162
+ var _a2;
12163
+ output += chunk;
12164
+ if (!watch)
12165
+ return;
12166
+ if (output.includes("File change detected") && !rerunTriggered) {
12167
+ (_a2 = this._onWatcherRerun) == null ? void 0 : _a2.call(this);
12168
+ this._result.sourceErrors = [];
12169
+ this._result.files = [];
12170
+ this._tests = null;
12171
+ rerunTriggered = true;
12172
+ }
12173
+ if (/Found \w+ errors*. Watching for/.test(output)) {
12174
+ rerunTriggered = false;
12175
+ this.prepareResults(output).then((result) => {
12176
+ var _a3;
12177
+ this._result = result;
12178
+ (_a3 = this._onParseEnd) == null ? void 0 : _a3.call(this, result);
12179
+ });
12180
+ output = "";
12181
+ }
12182
+ });
12183
+ if (!watch) {
12184
+ await child;
12185
+ this._result = await this.prepareResults(output);
12186
+ await ((_c = this._onParseEnd) == null ? void 0 : _c.call(this, this._result));
12493
12187
  }
12494
- if (isFileUrl(input))
12495
- return parseFileUrl(input);
12496
- if (isAbsoluteUrl(input))
12497
- return parseAbsoluteUrl(input);
12498
- const url = parseAbsoluteUrl('http://foo.com/' + input);
12499
- url.scheme = '';
12500
- url.host = '';
12501
- url.type = input
12502
- ? input.startsWith('?')
12503
- ? UrlType.Query
12504
- : input.startsWith('#')
12505
- ? UrlType.Hash
12506
- : UrlType.RelativePath
12507
- : UrlType.Empty;
12508
- return url;
12509
- }
12510
- function stripPathFilename(path) {
12511
- // If a path ends with a parent directory "..", then it's a relative path with excess parent
12512
- // paths. It's not a file, so we can't strip it.
12513
- if (path.endsWith('/..'))
12514
- return path;
12515
- const index = path.lastIndexOf('/');
12516
- return path.slice(0, index + 1);
12188
+ }
12189
+ getResult() {
12190
+ return this._result;
12191
+ }
12192
+ getTestFiles() {
12193
+ return Object.values(this._tests || {}).map((i) => i.file);
12194
+ }
12195
+ getTestPacks() {
12196
+ return Object.values(this._tests || {}).map(({ file }) => getTasks(file)).flat().map((i) => [i.id, void 0]);
12197
+ }
12517
12198
  }
12518
- function mergePaths(url, base) {
12519
- normalizePath(base, base.type);
12520
- // If the path is just a "/", then it was an empty path to begin with (remember, we're a relative
12521
- // path).
12522
- if (url.path === '/') {
12523
- url.path = base.path;
12524
- }
12525
- else {
12526
- // Resolution happens relative to the base path's directory, not the file.
12527
- url.path = stripPathFilename(base.path) + url.path;
12528
- }
12199
+
12200
+ async function printError(error, ctx, options = {}) {
12201
+ const { showCodeFrame = true, fullStack = false, type } = options;
12202
+ let e = error;
12203
+ if (isPrimitive(e)) {
12204
+ e = {
12205
+ message: String(error).split(/\n/g)[0],
12206
+ stack: String(error)
12207
+ };
12208
+ }
12209
+ if (!e) {
12210
+ const error2 = new Error("unknown error");
12211
+ e = {
12212
+ message: e ?? error2.message,
12213
+ stack: error2.stack
12214
+ };
12215
+ }
12216
+ if (!ctx.config)
12217
+ return printErrorMessage(e, ctx.logger);
12218
+ const stacks = parseErrorStacktrace(e, fullStack ? [] : void 0);
12219
+ const nearest = error instanceof TypeCheckError ? error.stacks[0] : stacks.find(
12220
+ (stack) => ctx.getModuleProjects(stack.file).length && existsSync(stack.file)
12221
+ );
12222
+ const errorProperties = getErrorProperties(e);
12223
+ if (type)
12224
+ printErrorType(type, ctx);
12225
+ printErrorMessage(e, ctx.logger);
12226
+ if (e.frame) {
12227
+ ctx.logger.error(c.yellow(e.frame));
12228
+ } else {
12229
+ printStack(ctx, stacks, nearest, errorProperties, (s) => {
12230
+ if (showCodeFrame && s === nearest && nearest) {
12231
+ const sourceCode = readFileSync(nearest.file, "utf-8");
12232
+ ctx.logger.error(c.yellow(generateCodeFrame(sourceCode, 4, s.line, s.column)));
12233
+ }
12234
+ });
12235
+ }
12236
+ const testPath = e.VITEST_TEST_PATH;
12237
+ const testName = e.VITEST_TEST_NAME;
12238
+ const afterEnvTeardown = e.VITEST_AFTER_ENV_TEARDOWN;
12239
+ if (testPath)
12240
+ ctx.logger.error(c.red(`This error originated in "${c.bold(testPath)}" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.`));
12241
+ if (testName) {
12242
+ ctx.logger.error(c.red(`The latest test that might've caused the error is "${c.bold(testName)}". It might mean one of the following:
12243
+ - The error was thrown, while Vitest was running this test.
12244
+ - This was the last recorded test before the error was thrown, if error originated after test finished its execution.`));
12245
+ }
12246
+ if (afterEnvTeardown) {
12247
+ ctx.logger.error(c.red("This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes:\n- cancel timeouts using clearTimeout and clearInterval\n- wait for promises to resolve using the await keyword"));
12248
+ }
12249
+ if (typeof e.cause === "object" && e.cause && "name" in e.cause) {
12250
+ e.cause.name = `Caused by: ${e.cause.name}`;
12251
+ await printError(e.cause, ctx, { fullStack, showCodeFrame: false });
12252
+ }
12253
+ handleImportOutsideModuleError(e.stack || e.stackStr || "", ctx);
12254
+ if (e.diff)
12255
+ displayDiff(e.diff, ctx.logger.console);
12529
12256
  }
12530
- /**
12531
- * The path can have empty directories "//", unneeded parents "foo/..", or current directory
12532
- * "foo/.". We need to normalize to a standard representation.
12533
- */
12534
- function normalizePath(url, type) {
12535
- const rel = type <= UrlType.RelativePath;
12536
- const pieces = url.path.split('/');
12537
- // We need to preserve the first piece always, so that we output a leading slash. The item at
12538
- // pieces[0] is an empty string.
12539
- let pointer = 1;
12540
- // Positive is the number of real directories we've output, used for popping a parent directory.
12541
- // Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
12542
- let positive = 0;
12543
- // We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
12544
- // generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
12545
- // real directory, we won't need to append, unless the other conditions happen again.
12546
- let addTrailingSlash = false;
12547
- for (let i = 1; i < pieces.length; i++) {
12548
- const piece = pieces[i];
12549
- // An empty directory, could be a trailing slash, or just a double "//" in the path.
12550
- if (!piece) {
12551
- addTrailingSlash = true;
12552
- continue;
12553
- }
12554
- // If we encounter a real directory, then we don't need to append anymore.
12555
- addTrailingSlash = false;
12556
- // A current directory, which we can always drop.
12557
- if (piece === '.')
12558
- continue;
12559
- // A parent directory, we need to see if there are any real directories we can pop. Else, we
12560
- // have an excess of parents, and we'll need to keep the "..".
12561
- if (piece === '..') {
12562
- if (positive) {
12563
- addTrailingSlash = true;
12564
- positive--;
12565
- pointer--;
12566
- }
12567
- else if (rel) {
12568
- // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
12569
- // URL, protocol relative URL, or an absolute path, we don't need to keep excess.
12570
- pieces[pointer++] = piece;
12571
- }
12572
- continue;
12573
- }
12574
- // We've encountered a real directory. Move it to the next insertion pointer, which accounts for
12575
- // any popped or dropped directories.
12576
- pieces[pointer++] = piece;
12577
- positive++;
12578
- }
12579
- let path = '';
12580
- for (let i = 1; i < pointer; i++) {
12581
- path += '/' + pieces[i];
12582
- }
12583
- if (!path || (addTrailingSlash && !path.endsWith('/..'))) {
12584
- path += '/';
12585
- }
12586
- url.path = path;
12257
+ function printErrorType(type, ctx) {
12258
+ ctx.logger.error(`
12259
+ ${c.red(divider(c.bold(c.inverse(` ${type} `))))}`);
12587
12260
  }
12588
- /**
12589
- * Attempts to resolve `input` URL/path relative to `base`.
12590
- */
12591
- function resolve$1(input, base) {
12592
- if (!input && !base)
12593
- return '';
12594
- const url = parseUrl(input);
12595
- let inputType = url.type;
12596
- if (base && inputType !== UrlType.Absolute) {
12597
- const baseUrl = parseUrl(base);
12598
- const baseType = baseUrl.type;
12599
- switch (inputType) {
12600
- case UrlType.Empty:
12601
- url.hash = baseUrl.hash;
12602
- // fall through
12603
- case UrlType.Hash:
12604
- url.query = baseUrl.query;
12605
- // fall through
12606
- case UrlType.Query:
12607
- case UrlType.RelativePath:
12608
- mergePaths(url, baseUrl);
12609
- // fall through
12610
- case UrlType.AbsolutePath:
12611
- // The host, user, and port are joined, you can't copy one without the others.
12612
- url.user = baseUrl.user;
12613
- url.host = baseUrl.host;
12614
- url.port = baseUrl.port;
12615
- // fall through
12616
- case UrlType.SchemeRelative:
12617
- // The input doesn't have a schema at least, so we need to copy at least that over.
12618
- url.scheme = baseUrl.scheme;
12619
- }
12620
- if (baseType > inputType)
12621
- inputType = baseType;
12622
- }
12623
- normalizePath(url, inputType);
12624
- const queryHash = url.query + url.hash;
12625
- switch (inputType) {
12626
- // This is impossible, because of the empty checks at the start of the function.
12627
- // case UrlType.Empty:
12628
- case UrlType.Hash:
12629
- case UrlType.Query:
12630
- return queryHash;
12631
- case UrlType.RelativePath: {
12632
- // The first char is always a "/", and we need it to be relative.
12633
- const path = url.path.slice(1);
12634
- if (!path)
12635
- return queryHash || '.';
12636
- if (isRelative(base || input) && !isRelative(path)) {
12637
- // If base started with a leading ".", or there is no base and input started with a ".",
12638
- // then we need to ensure that the relative path starts with a ".". We don't know if
12639
- // relative starts with a "..", though, so check before prepending.
12640
- return './' + path + queryHash;
12641
- }
12642
- return path + queryHash;
12643
- }
12644
- case UrlType.AbsolutePath:
12645
- return url.path + queryHash;
12646
- default:
12647
- return url.scheme + '//' + url.user + url.host + url.port + url.path + queryHash;
12648
- }
12261
+ const skipErrorProperties = /* @__PURE__ */ new Set([
12262
+ "nameStr",
12263
+ "stack",
12264
+ "cause",
12265
+ "stacks",
12266
+ "stackStr",
12267
+ "type",
12268
+ "showDiff",
12269
+ "diff",
12270
+ "actual",
12271
+ "expected",
12272
+ "VITEST_TEST_NAME",
12273
+ "VITEST_TEST_PATH",
12274
+ "VITEST_AFTER_ENV_TEARDOWN",
12275
+ ...Object.getOwnPropertyNames(Error.prototype),
12276
+ ...Object.getOwnPropertyNames(Object.prototype)
12277
+ ]);
12278
+ function getErrorProperties(e) {
12279
+ const errorObject = /* @__PURE__ */ Object.create(null);
12280
+ if (e.name === "AssertionError")
12281
+ return errorObject;
12282
+ for (const key of Object.getOwnPropertyNames(e)) {
12283
+ if (!skipErrorProperties.has(key))
12284
+ errorObject[key] = e[key];
12285
+ }
12286
+ return errorObject;
12649
12287
  }
12650
-
12651
- function resolve(input, base) {
12652
- // The base is always treated as a directory, if it's not empty.
12653
- // https://github.com/mozilla/source-map/blob/8cb3ee57/lib/util.js#L327
12654
- // https://github.com/chromium/chromium/blob/da4adbb3/third_party/blink/renderer/devtools/front_end/sdk/SourceMap.js#L400-L401
12655
- if (base && !base.endsWith('/'))
12656
- base += '/';
12657
- return resolve$1(input, base);
12288
+ const esmErrors = [
12289
+ "Cannot use import statement outside a module",
12290
+ "Unexpected token 'export'"
12291
+ ];
12292
+ function handleImportOutsideModuleError(stack, ctx) {
12293
+ if (!esmErrors.some((e) => stack.includes(e)))
12294
+ return;
12295
+ const path = normalize(stack.split("\n")[0].trim());
12296
+ let name = path.split("/node_modules/").pop() || "";
12297
+ if (name == null ? void 0 : name.startsWith("@"))
12298
+ name = name.split("/").slice(0, 2).join("/");
12299
+ else
12300
+ name = name.split("/")[0];
12301
+ if (name)
12302
+ printModuleWarningForPackage(ctx.logger, path, name);
12303
+ else
12304
+ printModuleWarningForSourceCode(ctx.logger, path);
12658
12305
  }
12306
+ function printModuleWarningForPackage(logger, path, name) {
12307
+ logger.error(c.yellow(
12308
+ `Module ${path} seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package ${c.bold(`"${name}"`)} asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
12659
12309
 
12660
- /**
12661
- * Removes everything after the last "/", but leaves the slash.
12662
- */
12663
- function stripFilename(path) {
12664
- if (!path)
12665
- return '';
12666
- const index = path.lastIndexOf('/');
12667
- return path.slice(0, index + 1);
12668
- }
12310
+ As a temporary workaround you can try to inline the package by updating your config:
12669
12311
 
12670
- const COLUMN = 0;
12312
+ ` + c.gray(c.dim("// vitest.config.js")) + "\n" + c.green(`export default {
12313
+ test: {
12314
+ deps: {
12315
+ inline: [
12316
+ ${c.yellow(c.bold(`"${name}"`))}
12317
+ ]
12318
+ }
12319
+ }
12320
+ }
12321
+ `)
12322
+ ));
12323
+ }
12324
+ function printModuleWarningForSourceCode(logger, path) {
12325
+ logger.error(c.yellow(
12326
+ `Module ${path} seems to be an ES Module but shipped in a CommonJS package. To fix this issue, change the file extension to .mjs or add "type": "module" in your package.json.`
12327
+ ));
12328
+ }
12329
+ function displayDiff(diff, console) {
12330
+ console.error(diff);
12331
+ }
12332
+ function printErrorMessage(error, logger) {
12333
+ const errorName = error.name || error.nameStr || "Unknown Error";
12334
+ logger.error(c.red(`${c.bold(errorName)}: ${error.message}`));
12335
+ }
12336
+ function printStack(ctx, stack, highlight, errorProperties, onStack) {
12337
+ const logger = ctx.logger;
12338
+ for (const frame of stack) {
12339
+ const color = frame === highlight ? c.yellow : c.gray;
12340
+ const path = relative(ctx.config.root, frame.file);
12341
+ logger.error(color(` ${c.dim(F_POINTER)} ${[frame.method, c.dim(`${path}:${frame.line}:${frame.column}`)].filter(Boolean).join(" ")}`));
12342
+ onStack == null ? void 0 : onStack(frame);
12343
+ }
12344
+ if (stack.length)
12345
+ logger.error();
12346
+ const hasProperties = Object.keys(errorProperties).length > 0;
12347
+ if (hasProperties) {
12348
+ logger.error(c.red(c.dim(divider())));
12349
+ const propertiesString = stringify$5(errorProperties, 10, { printBasicPrototype: false });
12350
+ logger.error(c.red(c.bold("Serialized Error:")), c.gray(propertiesString));
12351
+ }
12352
+ }
12353
+ function generateCodeFrame(source, indent = 0, lineNumber, columnNumber, range = 2) {
12354
+ var _a;
12355
+ const start = positionToOffset(source, lineNumber, columnNumber);
12356
+ const end = start;
12357
+ const lines = source.split(lineSplitRE);
12358
+ let count = 0;
12359
+ let res = [];
12360
+ const columns = ((_a = process.stdout) == null ? void 0 : _a.columns) || 80;
12361
+ function lineNo(no = "") {
12362
+ return c.gray(`${String(no).padStart(3, " ")}| `);
12363
+ }
12364
+ for (let i = 0; i < lines.length; i++) {
12365
+ count += lines[i].length + 1;
12366
+ if (count >= start) {
12367
+ for (let j = i - range; j <= i + range || end > count; j++) {
12368
+ if (j < 0 || j >= lines.length)
12369
+ continue;
12370
+ const lineLength = lines[j].length;
12371
+ if (lineLength > 200)
12372
+ return "";
12373
+ res.push(lineNo(j + 1) + cliTruncate(lines[j].replace(/\t/g, " "), columns - 5 - indent));
12374
+ if (j === i) {
12375
+ const pad = start - (count - lineLength);
12376
+ const length = Math.max(1, end > count ? lineLength - pad : end - start);
12377
+ res.push(lineNo() + " ".repeat(pad) + c.red("^".repeat(length)));
12378
+ } else if (j > i) {
12379
+ if (end > count) {
12380
+ const length = Math.max(1, Math.min(end - count, lineLength));
12381
+ res.push(lineNo() + c.red("^".repeat(length)));
12382
+ }
12383
+ count += lineLength + 1;
12384
+ }
12385
+ }
12386
+ break;
12387
+ }
12388
+ }
12389
+ if (indent)
12390
+ res = res.map((line) => " ".repeat(indent) + line);
12391
+ return res.join("\n");
12392
+ }
12671
12393
 
12672
- function maybeSort(mappings, owned) {
12673
- const unsortedIndex = nextUnsortedSegmentLine(mappings, 0);
12674
- if (unsortedIndex === mappings.length)
12675
- return mappings;
12676
- // If we own the array (meaning we parsed it from JSON), then we're free to directly mutate it. If
12677
- // not, we do not want to modify the consumer's input array.
12678
- if (!owned)
12679
- mappings = mappings.slice();
12680
- for (let i = unsortedIndex; i < mappings.length; i = nextUnsortedSegmentLine(mappings, i + 1)) {
12681
- mappings[i] = sortSegments(mappings[i], owned);
12394
+ class Logger {
12395
+ constructor(ctx, console = globalThis.console) {
12396
+ this.ctx = ctx;
12397
+ this.console = console;
12398
+ this.outputStream = process.stdout;
12399
+ this.errorStream = process.stderr;
12400
+ this.logUpdate = createLogUpdate(process.stdout);
12401
+ }
12402
+ log(...args) {
12403
+ this._clearScreen();
12404
+ this.console.log(...args);
12405
+ }
12406
+ error(...args) {
12407
+ this._clearScreen();
12408
+ this.console.error(...args);
12409
+ }
12410
+ warn(...args) {
12411
+ this._clearScreen();
12412
+ this.console.warn(...args);
12413
+ }
12414
+ clearFullScreen(message) {
12415
+ if (this.ctx.server.config.clearScreen === false) {
12416
+ this.console.log(message);
12417
+ return;
12682
12418
  }
12683
- return mappings;
12419
+ this.console.log(`\x1Bc${message}`);
12420
+ }
12421
+ clearScreen(message, force = false) {
12422
+ if (this.ctx.server.config.clearScreen === false) {
12423
+ this.console.log(message);
12424
+ return;
12425
+ }
12426
+ this._clearScreenPending = message;
12427
+ if (force)
12428
+ this._clearScreen();
12429
+ }
12430
+ _clearScreen() {
12431
+ if (this._clearScreenPending == null)
12432
+ return;
12433
+ const log = this._clearScreenPending;
12434
+ this._clearScreenPending = void 0;
12435
+ this.console.log(`\x1B[1;1H\x1B[J${log}`);
12436
+ }
12437
+ printError(err, fullStack = false, type) {
12438
+ return printError(err, this.ctx, {
12439
+ fullStack,
12440
+ type,
12441
+ showCodeFrame: true
12442
+ });
12443
+ }
12444
+ printNoTestFound(filters) {
12445
+ const config = this.ctx.config;
12446
+ const comma = c.dim(", ");
12447
+ if (filters == null ? void 0 : filters.length)
12448
+ this.console.error(c.dim("filter: ") + c.yellow(filters.join(comma)));
12449
+ if (config.include)
12450
+ this.console.error(c.dim("include: ") + c.yellow(config.include.join(comma)));
12451
+ if (config.exclude)
12452
+ this.console.error(c.dim("exclude: ") + c.yellow(config.exclude.join(comma)));
12453
+ if (config.watchExclude)
12454
+ this.console.error(c.dim("watch exclude: ") + c.yellow(config.watchExclude.join(comma)));
12455
+ if (config.passWithNoTests)
12456
+ this.log(`No ${config.mode} files found, exiting with code 0
12457
+ `);
12458
+ else
12459
+ this.error(c.red(`
12460
+ No ${config.mode} files found, exiting with code 1`));
12461
+ }
12462
+ printBanner() {
12463
+ var _a, _b;
12464
+ this.log();
12465
+ const versionTest = this.ctx.config.watch ? c.blue(`v${version}`) : c.cyan(`v${version}`);
12466
+ const mode = this.ctx.config.watch ? c.blue(" DEV ") : c.cyan(" RUN ");
12467
+ this.log(`${c.inverse(c.bold(mode))} ${versionTest} ${c.gray(this.ctx.config.root)}`);
12468
+ if (this.ctx.config.sequence.sequencer === RandomSequencer)
12469
+ this.log(c.gray(` Running tests with seed "${this.ctx.config.sequence.seed}"`));
12470
+ this.ctx.projects.forEach((project) => {
12471
+ var _a2;
12472
+ if (!project.browser)
12473
+ return;
12474
+ const name = project.getName();
12475
+ const output = project.isCore() ? "" : ` [${name}]`;
12476
+ this.log(c.dim(c.green(` ${output} Browser runner started at http://${((_a2 = project.config.browser.api) == null ? void 0 : _a2.host) || "localhost"}:${c.bold(`${project.browser.config.server.port}`)}`)));
12477
+ });
12478
+ if (this.ctx.config.ui)
12479
+ this.log(c.dim(c.green(` UI started at http://${((_a = this.ctx.config.api) == null ? void 0 : _a.host) || "localhost"}:${c.bold(`${this.ctx.server.config.server.port}`)}${this.ctx.config.uiBase}`)));
12480
+ else if (this.ctx.config.api)
12481
+ this.log(c.dim(c.green(` API started at http://${((_b = this.ctx.config.api) == null ? void 0 : _b.host) || "localhost"}:${c.bold(`${this.ctx.config.api.port}`)}`)));
12482
+ if (this.ctx.coverageProvider)
12483
+ this.log(c.dim(" Coverage enabled with ") + c.yellow(this.ctx.coverageProvider.name));
12484
+ this.log();
12485
+ }
12486
+ async printUnhandledErrors(errors) {
12487
+ const errorMessage = c.red(c.bold(
12488
+ `
12489
+ Vitest caught ${errors.length} unhandled error${errors.length > 1 ? "s" : ""} during the test run.
12490
+ This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.`
12491
+ ));
12492
+ this.log(c.red(divider(c.bold(c.inverse(" Unhandled Errors ")))));
12493
+ this.log(errorMessage);
12494
+ await Promise.all(errors.map(async (err) => {
12495
+ await this.printError(err, true, err.type || "Unhandled Error");
12496
+ }));
12497
+ this.log(c.red(divider()));
12498
+ }
12499
+ async printSourceTypeErrors(errors) {
12500
+ const errorMessage = c.red(c.bold(
12501
+ `
12502
+ Vitest found ${errors.length} error${errors.length > 1 ? "s" : ""} not related to your test files.`
12503
+ ));
12504
+ this.log(c.red(divider(c.bold(c.inverse(" Source Errors ")))));
12505
+ this.log(errorMessage);
12506
+ await Promise.all(errors.map(async (err) => {
12507
+ await this.printError(err, true);
12508
+ }));
12509
+ this.log(c.red(divider()));
12510
+ }
12684
12511
  }
12685
- function nextUnsortedSegmentLine(mappings, start) {
12686
- for (let i = start; i < mappings.length; i++) {
12687
- if (!isSorted(mappings[i]))
12688
- return i;
12512
+
12513
+ function CoverageTransform(ctx) {
12514
+ return {
12515
+ name: "vitest:coverage-transform",
12516
+ transform(srcCode, id) {
12517
+ var _a, _b;
12518
+ return (_b = (_a = ctx.coverageProvider) == null ? void 0 : _a.onFileTransform) == null ? void 0 : _b.call(_a, srcCode, normalizeRequestId(id), this);
12689
12519
  }
12690
- return mappings.length;
12520
+ };
12691
12521
  }
12692
- function isSorted(line) {
12693
- for (let j = 1; j < line.length; j++) {
12694
- if (line[j][COLUMN] < line[j - 1][COLUMN]) {
12695
- return false;
12696
- }
12522
+
12523
+ const API_NOT_FOUND_ERROR = `There are some problems in resolving the mocks API.
12524
+ You may encounter this issue when importing the mocks API from another module other than 'vitest'.
12525
+ To fix this issue you can either:
12526
+ - import the mocks API directly from 'vitest'
12527
+ - enable the 'globals' options`;
12528
+ const API_NOT_FOUND_CHECK = `
12529
+ if (typeof globalThis.vi === "undefined" && typeof globalThis.vitest === "undefined") { throw new Error(${JSON.stringify(API_NOT_FOUND_ERROR)}) }
12530
+ `;
12531
+ function isIdentifier(node) {
12532
+ return node.type === "Identifier";
12533
+ }
12534
+ function transformImportSpecifiers(node) {
12535
+ const specifiers = node.specifiers;
12536
+ if (specifiers.length === 1 && specifiers[0].type === "ImportNamespaceSpecifier")
12537
+ return specifiers[0].local.name;
12538
+ const dynamicImports = node.specifiers.map((specifier) => {
12539
+ if (specifier.type === "ImportDefaultSpecifier")
12540
+ return `default: ${specifier.local.name}`;
12541
+ if (specifier.type === "ImportSpecifier") {
12542
+ const local = specifier.local.name;
12543
+ const imported = specifier.imported.name;
12544
+ if (local === imported)
12545
+ return local;
12546
+ return `${imported}: ${local}`;
12697
12547
  }
12698
- return true;
12699
- }
12700
- function sortSegments(line, owned) {
12701
- if (!owned)
12702
- line = line.slice();
12703
- return line.sort(sortComparator);
12704
- }
12705
- function sortComparator(a, b) {
12706
- return a[COLUMN] - b[COLUMN];
12548
+ return null;
12549
+ }).filter(Boolean).join(", ");
12550
+ if (!dynamicImports.length)
12551
+ return "";
12552
+ return `{ ${dynamicImports} }`;
12707
12553
  }
12708
-
12709
- let found = false;
12710
- /**
12711
- * A binary search implementation that returns the index if a match is found.
12712
- * If no match is found, then the left-index (the index associated with the item that comes just
12713
- * before the desired index) is returned. To maintain proper sort order, a splice would happen at
12714
- * the next index:
12715
- *
12716
- * ```js
12717
- * const array = [1, 3];
12718
- * const needle = 2;
12719
- * const index = binarySearch(array, needle, (item, needle) => item - needle);
12720
- *
12721
- * assert.equal(index, 0);
12722
- * array.splice(index + 1, 0, needle);
12723
- * assert.deepEqual(array, [1, 2, 3]);
12724
- * ```
12725
- */
12726
- function binarySearch(haystack, needle, low, high) {
12727
- while (low <= high) {
12728
- const mid = low + ((high - low) >> 1);
12729
- const cmp = haystack[mid][COLUMN] - needle;
12730
- if (cmp === 0) {
12731
- found = true;
12732
- return mid;
12733
- }
12734
- if (cmp < 0) {
12735
- low = mid + 1;
12554
+ const regexpHoistable = /^[ \t]*\b(vi|vitest)\s*\.\s*(mock|unmock|hoisted)\(/m;
12555
+ const hashbangRE = /^#!.*\n/;
12556
+ function hoistMocks(code, id, parse) {
12557
+ var _a;
12558
+ const hasMocks = regexpHoistable.test(code);
12559
+ if (!hasMocks)
12560
+ return;
12561
+ const s = new MagicString(code);
12562
+ let ast;
12563
+ try {
12564
+ ast = parse(code, {
12565
+ sourceType: "module",
12566
+ ecmaVersion: "latest",
12567
+ locations: true
12568
+ });
12569
+ } catch (err) {
12570
+ console.error(`Cannot parse ${id}:
12571
+ ${err.message}`);
12572
+ return;
12573
+ }
12574
+ const hoistIndex = ((_a = code.match(hashbangRE)) == null ? void 0 : _a[0].length) ?? 0;
12575
+ let hoistedCode = "";
12576
+ let hoistedVitestImports = "";
12577
+ const transformImportDeclaration = (node) => {
12578
+ const source = node.source.value;
12579
+ const specifiers = transformImportSpecifiers(node);
12580
+ const code2 = specifiers ? `const ${specifiers} = await import('${source}')
12581
+ ` : `await import('${source}')
12582
+ `;
12583
+ return code2;
12584
+ };
12585
+ function hoistImport(node) {
12586
+ s.remove(node.start, node.end);
12587
+ if (node.source.value === "vitest") {
12588
+ const code3 = `const ${transformImportSpecifiers(node)} = await import('vitest')
12589
+ `;
12590
+ hoistedVitestImports += code3;
12591
+ return;
12592
+ }
12593
+ const code2 = transformImportDeclaration(node);
12594
+ s.appendLeft(hoistIndex, code2);
12595
+ }
12596
+ for (const node of ast.body) {
12597
+ if (node.type === "ImportDeclaration")
12598
+ hoistImport(node);
12599
+ }
12600
+ simple(ast, {
12601
+ CallExpression(_node) {
12602
+ var _a2, _b;
12603
+ const node = _node;
12604
+ if (node.callee.type === "MemberExpression" && isIdentifier(node.callee.object) && (node.callee.object.name === "vi" || node.callee.object.name === "vitest") && isIdentifier(node.callee.property)) {
12605
+ const methodName = node.callee.property.name;
12606
+ if (methodName === "mock" || methodName === "unmock") {
12607
+ hoistedCode += `${code.slice(node.start, node.end)}
12608
+ `;
12609
+ s.remove(node.start, node.end);
12736
12610
  }
12737
- else {
12738
- high = mid - 1;
12611
+ if (methodName === "hoisted") {
12612
+ const declarationNode = (_a2 = findNodeAround(ast, node.start, "VariableDeclaration")) == null ? void 0 : _a2.node;
12613
+ const init = (_b = declarationNode == null ? void 0 : declarationNode.declarations[0]) == null ? void 0 : _b.init;
12614
+ const isViHoisted = (node2) => {
12615
+ return node2.callee.type === "MemberExpression" && isIdentifier(node2.callee.object) && (node2.callee.object.name === "vi" || node2.callee.object.name === "vitest") && isIdentifier(node2.callee.property) && node2.callee.property.name === "hoisted";
12616
+ };
12617
+ const canMoveDeclaration = init && init.type === "CallExpression" && isViHoisted(init) || init && init.type === "AwaitExpression" && init.argument.type === "CallExpression" && isViHoisted(init.argument);
12618
+ if (canMoveDeclaration) {
12619
+ hoistedCode += `${code.slice(declarationNode.start, declarationNode.end)}
12620
+ `;
12621
+ s.remove(declarationNode.start, declarationNode.end);
12622
+ } else {
12623
+ hoistedCode += `${code.slice(node.start, node.end)}
12624
+ `;
12625
+ s.remove(node.start, node.end);
12626
+ }
12739
12627
  }
12628
+ }
12740
12629
  }
12741
- found = false;
12742
- return low - 1;
12743
- }
12744
- function upperBound(haystack, needle, index) {
12745
- for (let i = index + 1; i < haystack.length; index = i++) {
12746
- if (haystack[i][COLUMN] !== needle)
12747
- break;
12748
- }
12749
- return index;
12630
+ });
12631
+ if (hoistedCode || hoistedVitestImports) {
12632
+ s.prepend(
12633
+ hoistedVitestImports + (!hoistedVitestImports && hoistedCode ? API_NOT_FOUND_CHECK : "") + hoistedCode
12634
+ );
12635
+ }
12636
+ return {
12637
+ ast,
12638
+ code: s.toString(),
12639
+ map: s.generateMap({ hires: true, source: id })
12640
+ };
12750
12641
  }
12751
- function lowerBound(haystack, needle, index) {
12752
- for (let i = index - 1; i >= 0; index = i--) {
12753
- if (haystack[i][COLUMN] !== needle)
12754
- break;
12642
+
12643
+ function MocksPlugin() {
12644
+ return {
12645
+ name: "vite:mocks",
12646
+ enforce: "post",
12647
+ transform(code, id) {
12648
+ return hoistMocks(code, id, this.parse);
12755
12649
  }
12756
- return index;
12757
- }
12758
- function memoizedState() {
12759
- return {
12760
- lastKey: -1,
12761
- lastNeedle: -1,
12762
- lastIndex: -1,
12763
- };
12650
+ };
12764
12651
  }
12765
- /**
12766
- * This overly complicated beast is just to record the last tested line/column and the resulting
12767
- * index, allowing us to skip a few tests if mappings are monotonically increasing.
12768
- */
12769
- function memoizedBinarySearch(haystack, needle, state, key) {
12770
- const { lastKey, lastNeedle, lastIndex } = state;
12771
- let low = 0;
12772
- let high = haystack.length - 1;
12773
- if (key === lastKey) {
12774
- if (needle === lastNeedle) {
12775
- found = lastIndex !== -1 && haystack[lastIndex][COLUMN] === needle;
12776
- return lastIndex;
12777
- }
12778
- if (needle >= lastNeedle) {
12779
- // lastIndex may be -1 if the previous needle was not found.
12780
- low = lastIndex === -1 ? 0 : lastIndex;
12781
- }
12782
- else {
12783
- high = lastIndex;
12652
+
12653
+ async function createBrowserServer(project, options) {
12654
+ const root = project.config.root;
12655
+ await ensurePackageInstalled("@vitest/browser", root);
12656
+ const configPath = options.config === false ? false : options.config ? resolve$2(root, options.config) : await findUp(configFiles, { cwd: root });
12657
+ const server = await createServer({
12658
+ logLevel: "error",
12659
+ mode: project.config.mode,
12660
+ configFile: configPath,
12661
+ // watch is handled by Vitest
12662
+ server: {
12663
+ hmr: false,
12664
+ watch: {
12665
+ ignored: ["**/**"]
12666
+ }
12667
+ },
12668
+ plugins: [
12669
+ (await import('@vitest/browser')).default(project, "/"),
12670
+ CoverageTransform(project.ctx),
12671
+ {
12672
+ enforce: "post",
12673
+ name: "vitest:browser:config",
12674
+ async config(config) {
12675
+ var _a, _b, _c;
12676
+ const server2 = resolveApiServerConfig(((_a = config.test) == null ? void 0 : _a.browser) || {}) || {
12677
+ port: defaultBrowserPort
12678
+ };
12679
+ config.server = server2;
12680
+ (_b = config.server).fs ?? (_b.fs = {});
12681
+ config.server.fs.strict = false;
12682
+ return {
12683
+ resolve: {
12684
+ alias: (_c = config.test) == null ? void 0 : _c.alias
12685
+ }
12686
+ };
12784
12687
  }
12785
- }
12786
- state.lastKey = key;
12787
- state.lastNeedle = needle;
12788
- return (state.lastIndex = binarySearch(haystack, needle, low, high));
12688
+ },
12689
+ MocksPlugin()
12690
+ ]
12691
+ });
12692
+ await server.listen();
12693
+ await server.watcher.close();
12694
+ (await import('./chunk-api-setup.df3106cd.js')).setup(project, server);
12695
+ return server;
12789
12696
  }
12790
- const LEAST_UPPER_BOUND = -1;
12791
- const GREATEST_LOWER_BOUND = 1;
12792
- /**
12793
- * Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
12794
- */
12795
- let decodedMappings;
12796
- /**
12797
- * A low-level API to find the segment associated with a generated line/column (think, from a
12798
- * stack trace). Line and column here are 0-based, unlike `originalPositionFor`.
12799
- */
12800
- let traceSegment;
12801
- class TraceMap {
12802
- constructor(map, mapUrl) {
12803
- const isString = typeof map === 'string';
12804
- if (!isString && map._decodedMemo)
12805
- return map;
12806
- const parsed = (isString ? JSON.parse(map) : map);
12807
- const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
12808
- this.version = version;
12809
- this.file = file;
12810
- this.names = names;
12811
- this.sourceRoot = sourceRoot;
12812
- this.sources = sources;
12813
- this.sourcesContent = sourcesContent;
12814
- const from = resolve(sourceRoot || '', stripFilename(mapUrl));
12815
- this.resolvedSources = sources.map((s) => resolve(s || '', from));
12816
- const { mappings } = parsed;
12817
- if (typeof mappings === 'string') {
12818
- this._encoded = mappings;
12819
- this._decoded = undefined;
12820
- }
12821
- else {
12822
- this._encoded = undefined;
12823
- this._decoded = maybeSort(mappings, isString);
12824
- }
12825
- this._decodedMemo = memoizedState();
12826
- this._bySources = undefined;
12827
- this._bySourceMemos = undefined;
12828
- }
12697
+
12698
+ const playwrightBrowsers = ["firefox", "webkit", "chromium"];
12699
+ class PlaywrightBrowserProvider {
12700
+ constructor() {
12701
+ this.name = "playwright";
12702
+ this.cachedBrowser = null;
12703
+ }
12704
+ getSupportedBrowsers() {
12705
+ return playwrightBrowsers;
12706
+ }
12707
+ async initialize(ctx, { browser }) {
12708
+ this.ctx = ctx;
12709
+ this.browser = browser;
12710
+ const root = this.ctx.config.root;
12711
+ if (!await ensurePackageInstalled("playwright", root))
12712
+ throw new Error('Cannot find "playwright" package. Please install it manually.');
12713
+ }
12714
+ async openBrowser() {
12715
+ if (this.cachedBrowser)
12716
+ return this.cachedBrowser;
12717
+ const options = this.ctx.config.browser;
12718
+ const playwright = await import('playwright');
12719
+ const playwrightInstance = await playwright[this.browser].launch({ headless: options.headless });
12720
+ this.cachedBrowser = await playwrightInstance.newPage();
12721
+ this.cachedBrowser.on("close", () => {
12722
+ playwrightInstance.close();
12723
+ });
12724
+ return this.cachedBrowser;
12725
+ }
12726
+ async openPage(url) {
12727
+ const browserInstance = await this.openBrowser();
12728
+ await browserInstance.goto(url);
12729
+ }
12730
+ async close() {
12731
+ var _a;
12732
+ await ((_a = this.cachedBrowser) == null ? void 0 : _a.close());
12733
+ process.exit();
12734
+ }
12829
12735
  }
12830
- (() => {
12831
- decodedMappings = (map) => {
12832
- return (map._decoded || (map._decoded = decode(map._encoded)));
12833
- };
12834
- traceSegment = (map, line, column) => {
12835
- const decoded = decodedMappings(map);
12836
- // It's common for parent source maps to have pointers to lines that have no
12837
- // mapping (like a "//# sourceMappingURL=") at the end of the child file.
12838
- if (line >= decoded.length)
12839
- return null;
12840
- const segments = decoded[line];
12841
- const index = traceSegmentInternal(segments, map._decodedMemo, line, column, GREATEST_LOWER_BOUND);
12842
- return index === -1 ? null : segments[index];
12736
+
12737
+ const webdriverBrowsers = ["firefox", "chrome", "edge", "safari"];
12738
+ class WebdriverBrowserProvider {
12739
+ constructor() {
12740
+ this.name = "webdriverio";
12741
+ this.cachedBrowser = null;
12742
+ this.stopSafari = () => {
12843
12743
  };
12844
- })();
12845
- function traceSegmentInternal(segments, memo, line, column, bias) {
12846
- let index = memoizedBinarySearch(segments, column, memo, line);
12847
- if (found) {
12848
- index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index);
12744
+ }
12745
+ getSupportedBrowsers() {
12746
+ return webdriverBrowsers;
12747
+ }
12748
+ async initialize(ctx, { browser }) {
12749
+ this.ctx = ctx;
12750
+ this.browser = browser;
12751
+ const root = this.ctx.config.root;
12752
+ if (!await ensurePackageInstalled("webdriverio", root))
12753
+ throw new Error('Cannot find "webdriverio" package. Please install it manually.');
12754
+ if (browser === "safari" && !await ensurePackageInstalled("safaridriver", root))
12755
+ throw new Error('Cannot find "safaridriver" package. Please install it manually.');
12756
+ }
12757
+ async openBrowser() {
12758
+ if (this.cachedBrowser)
12759
+ return this.cachedBrowser;
12760
+ const options = this.ctx.config.browser;
12761
+ if (this.browser === "safari") {
12762
+ const safaridriver = await import('safaridriver');
12763
+ safaridriver.start({ diagnose: true });
12764
+ this.stopSafari = () => safaridriver.stop();
12765
+ process.on("beforeExit", () => {
12766
+ safaridriver.stop();
12767
+ });
12849
12768
  }
12850
- else if (bias === LEAST_UPPER_BOUND)
12851
- index++;
12852
- if (index === -1 || index === segments.length)
12853
- return -1;
12854
- return index;
12769
+ const { remote } = await import('webdriverio');
12770
+ this.cachedBrowser = await remote({
12771
+ logLevel: "error",
12772
+ capabilities: {
12773
+ "browserName": this.browser,
12774
+ "wdio:devtoolsOptions": { headless: options.headless }
12775
+ }
12776
+ });
12777
+ return this.cachedBrowser;
12778
+ }
12779
+ async openPage(url) {
12780
+ const browserInstance = await this.openBrowser();
12781
+ await browserInstance.url(url);
12782
+ }
12783
+ async close() {
12784
+ var _a, _b, _c;
12785
+ await Promise.all([
12786
+ this.stopSafari(),
12787
+ ((_a = this.cachedBrowser) == null ? void 0 : _a.sessionId) ? (_c = (_b = this.cachedBrowser) == null ? void 0 : _b.deleteSession) == null ? void 0 : _c.call(_b) : null
12788
+ ]);
12789
+ process.exit();
12790
+ }
12855
12791
  }
12856
12792
 
12857
- /**
12858
- * Gets the index associated with `key` in the backing array, if it is already present.
12859
- */
12860
- let get;
12861
- /**
12862
- * Puts `key` into the backing array, if it is not already present. Returns
12863
- * the index of the `key` in the backing array.
12864
- */
12865
- let put;
12866
- /**
12867
- * SetArray acts like a `Set` (allowing only one occurrence of a string `key`), but provides the
12868
- * index of the `key` in the backing array.
12869
- *
12870
- * This is designed to allow synchronizing a second array with the contents of the backing array,
12871
- * like how in a sourcemap `sourcesContent[i]` is the source content associated with `source[i]`,
12872
- * and there are never duplicates.
12873
- */
12874
- class SetArray {
12875
- constructor() {
12876
- this._indexes = { __proto__: null };
12877
- this.array = [];
12878
- }
12793
+ async function getBrowserProvider(options, loader) {
12794
+ switch (options.provider) {
12795
+ case void 0:
12796
+ case "webdriverio":
12797
+ return WebdriverBrowserProvider;
12798
+ case "playwright":
12799
+ return PlaywrightBrowserProvider;
12800
+ }
12801
+ let customProviderModule;
12802
+ try {
12803
+ customProviderModule = await loader.executeId(options.provider);
12804
+ } catch (error) {
12805
+ throw new Error(`Failed to load custom BrowserProvider from ${options.provider}`, { cause: error });
12806
+ }
12807
+ if (customProviderModule.default == null)
12808
+ throw new Error(`Custom BrowserProvider loaded from ${options.provider} was not the default export`);
12809
+ return customProviderModule.default;
12879
12810
  }
12880
- (() => {
12881
- get = (strarr, key) => strarr._indexes[key];
12882
- put = (strarr, key) => {
12883
- // The key may or may not be present. If it is present, it's a number.
12884
- const index = get(strarr, key);
12885
- if (index !== undefined)
12886
- return index;
12887
- const { array, _indexes: indexes } = strarr;
12888
- return (indexes[key] = array.push(key) - 1);
12889
- };
12890
- })();
12891
12811
 
12892
- /**
12893
- * A low-level API to associate a generated position with an original source position. Line and
12894
- * column here are 0-based, unlike `addMapping`.
12895
- */
12896
- let addSegment;
12897
- /**
12898
- * Adds/removes the content of the source file to the source map.
12899
- */
12900
- let setSourceContent;
12901
- /**
12902
- * Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
12903
- * a sourcemap, or to JSON.stringify.
12904
- */
12905
- let decodedMap;
12906
- /**
12907
- * Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
12908
- * a sourcemap, or to JSON.stringify.
12909
- */
12910
- let encodedMap;
12911
- /**
12912
- * Provides the state to generate a sourcemap.
12913
- */
12914
- class GenMapping {
12915
- constructor({ file, sourceRoot } = {}) {
12916
- this._names = new SetArray();
12917
- this._sources = new SetArray();
12918
- this._sourcesContent = [];
12919
- this._mappings = [];
12920
- this.file = file;
12921
- this.sourceRoot = sourceRoot;
12922
- }
12923
- }
12924
- (() => {
12925
- addSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name) => {
12926
- const { _mappings: mappings, _sources: sources, _sourcesContent: sourcesContent, _names: names, } = map;
12927
- const line = getLine(mappings, genLine);
12928
- if (source == null) {
12929
- const seg = [genColumn];
12930
- const index = getColumnIndex(line, genColumn, seg);
12931
- return insert(line, index, seg);
12932
- }
12933
- const sourcesIndex = put(sources, source);
12934
- const seg = name
12935
- ? [genColumn, sourcesIndex, sourceLine, sourceColumn, put(names, name)]
12936
- : [genColumn, sourcesIndex, sourceLine, sourceColumn];
12937
- const index = getColumnIndex(line, genColumn, seg);
12938
- if (sourcesIndex === sourcesContent.length)
12939
- sourcesContent[sourcesIndex] = null;
12940
- insert(line, index, seg);
12941
- };
12942
- setSourceContent = (map, source, content) => {
12943
- const { _sources: sources, _sourcesContent: sourcesContent } = map;
12944
- sourcesContent[put(sources, source)] = content;
12945
- };
12946
- decodedMap = (map) => {
12947
- const { file, sourceRoot, _mappings: mappings, _sources: sources, _sourcesContent: sourcesContent, _names: names, } = map;
12948
- return {
12949
- version: 3,
12950
- file,
12951
- names: names.array,
12952
- sourceRoot: sourceRoot || undefined,
12953
- sources: sources.array,
12954
- sourcesContent,
12955
- mappings,
12956
- };
12957
- };
12958
- encodedMap = (map) => {
12959
- const decoded = decodedMap(map);
12960
- return Object.assign(Object.assign({}, decoded), { mappings: encode(decoded.mappings) });
12961
- };
12962
- })();
12963
- function getLine(mappings, index) {
12964
- for (let i = mappings.length; i <= index; i++) {
12965
- mappings[i] = [];
12966
- }
12967
- return mappings[index];
12968
- }
12969
- function getColumnIndex(line, column, seg) {
12970
- let index = line.length;
12971
- for (let i = index - 1; i >= 0; i--, index--) {
12972
- const current = line[i];
12973
- const col = current[0];
12974
- if (col > column)
12975
- continue;
12976
- if (col < column)
12977
- break;
12978
- const cmp = compare(current, seg);
12979
- if (cmp === 0)
12980
- return index;
12981
- if (cmp < 0)
12982
- break;
12983
- }
12984
- return index;
12985
- }
12986
- function compare(a, b) {
12987
- let cmp = compareNum(a.length, b.length);
12988
- if (cmp !== 0)
12989
- return cmp;
12990
- // We've already checked genColumn
12991
- if (a.length === 1)
12992
- return 0;
12993
- cmp = compareNum(a[1], b[1]);
12994
- if (cmp !== 0)
12995
- return cmp;
12996
- cmp = compareNum(a[2], b[2]);
12997
- if (cmp !== 0)
12998
- return cmp;
12999
- cmp = compareNum(a[3], b[3]);
13000
- if (cmp !== 0)
13001
- return cmp;
13002
- if (a.length === 4)
13003
- return 0;
13004
- return compareNum(a[4], b[4]);
13005
- }
13006
- function compareNum(a, b) {
13007
- return a - b;
12812
+ function generateCssFilenameHash(filepath) {
12813
+ return createHash("md5").update(filepath).digest("hex").slice(0, 6);
13008
12814
  }
13009
- function insert(array, index, value) {
13010
- if (index === -1)
13011
- return;
13012
- for (let i = array.length; i > index; i--) {
13013
- array[i] = array[i - 1];
13014
- }
13015
- array[index] = value;
12815
+ function generateScopedClassName(strategy, name, filename) {
12816
+ if (strategy === "scoped")
12817
+ return null;
12818
+ if (strategy === "non-scoped")
12819
+ return name;
12820
+ const hash = generateCssFilenameHash(filename);
12821
+ return `_${name}_${hash}`;
13016
12822
  }
13017
12823
 
13018
- const SOURCELESS_MAPPING = {
13019
- source: null,
13020
- column: null,
13021
- line: null,
13022
- name: null,
13023
- content: null,
13024
- };
13025
- const EMPTY_SOURCES = [];
13026
- function Source(map, sources, source, content) {
13027
- return {
13028
- map,
13029
- sources,
13030
- source,
13031
- content,
13032
- };
13033
- }
13034
- /**
13035
- * MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes
13036
- * (which may themselves be SourceMapTrees).
13037
- */
13038
- function MapSource(map, sources) {
13039
- return Source(map, sources, '', null);
13040
- }
13041
- /**
13042
- * A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive
13043
- * segment tracing ends at the `OriginalSource`.
13044
- */
13045
- function OriginalSource(source, content) {
13046
- return Source(null, EMPTY_SOURCES, source, content);
13047
- }
13048
- /**
13049
- * traceMappings is only called on the root level SourceMapTree, and begins the process of
13050
- * resolving each mapping in terms of the original source files.
13051
- */
13052
- function traceMappings(tree) {
13053
- const gen = new GenMapping({ file: tree.map.file });
13054
- const { sources: rootSources, map } = tree;
13055
- const rootNames = map.names;
13056
- const rootMappings = decodedMappings(map);
13057
- for (let i = 0; i < rootMappings.length; i++) {
13058
- const segments = rootMappings[i];
13059
- let lastSource = null;
13060
- let lastSourceLine = null;
13061
- let lastSourceColumn = null;
13062
- for (let j = 0; j < segments.length; j++) {
13063
- const segment = segments[j];
13064
- const genCol = segment[0];
13065
- let traced = SOURCELESS_MAPPING;
13066
- // 1-length segments only move the current generated column, there's no source information
13067
- // to gather from it.
13068
- if (segment.length !== 1) {
13069
- const source = rootSources[segment[1]];
13070
- traced = originalPositionFor(source, segment[2], segment[3], segment.length === 5 ? rootNames[segment[4]] : '');
13071
- // If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
13072
- // respective segment into an original source.
13073
- if (traced == null)
13074
- continue;
13075
- }
13076
- // So we traced a segment down into its original source file. Now push a
13077
- // new segment pointing to this location.
13078
- const { column, line, name, content, source } = traced;
13079
- if (line === lastSourceLine && column === lastSourceColumn && source === lastSource) {
13080
- continue;
13081
- }
13082
- lastSourceLine = line;
13083
- lastSourceColumn = column;
13084
- lastSource = source;
13085
- // Sigh, TypeScript can't figure out source/line/column are either all null, or all non-null...
13086
- addSegment(gen, i, genCol, source, line, column, name);
13087
- if (content != null)
13088
- setSourceContent(gen, source, content);
13089
- }
13090
- }
13091
- return gen;
13092
- }
13093
- /**
13094
- * originalPositionFor is only called on children SourceMapTrees. It recurses down into its own
13095
- * child SourceMapTrees, until we find the original source map.
13096
- */
13097
- function originalPositionFor(source, line, column, name) {
13098
- if (!source.map) {
13099
- return { column, line, name, source: source.source, content: source.content };
13100
- }
13101
- const segment = traceSegment(source.map, line, column);
13102
- // If we couldn't find a segment, then this doesn't exist in the sourcemap.
13103
- if (segment == null)
13104
- return null;
13105
- // 1-length segments only move the current generated column, there's no source information
13106
- // to gather from it.
13107
- if (segment.length === 1)
13108
- return SOURCELESS_MAPPING;
13109
- return originalPositionFor(source.sources[segment[1]], segment[2], segment[3], segment.length === 5 ? source.map.names[segment[4]] : name);
12824
+ const cssLangs = "\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)";
12825
+ const cssLangRE = new RegExp(cssLangs);
12826
+ const cssModuleRE = new RegExp(`\\.module${cssLangs}`);
12827
+ function isCSS(id) {
12828
+ return cssLangRE.test(id);
13110
12829
  }
13111
-
13112
- function asArray(value) {
13113
- if (Array.isArray(value))
13114
- return value;
13115
- return [value];
12830
+ function isCSSModule(id) {
12831
+ return cssModuleRE.test(id);
13116
12832
  }
13117
- /**
13118
- * Recursively builds a tree structure out of sourcemap files, with each node
13119
- * being either an `OriginalSource` "leaf" or a `SourceMapTree` composed of
13120
- * `OriginalSource`s and `SourceMapTree`s.
13121
- *
13122
- * Every sourcemap is composed of a collection of source files and mappings
13123
- * into locations of those source files. When we generate a `SourceMapTree` for
13124
- * the sourcemap, we attempt to load each source file's own sourcemap. If it
13125
- * does not have an associated sourcemap, it is considered an original,
13126
- * unmodified source file.
13127
- */
13128
- function buildSourceMapTree(input, loader) {
13129
- const maps = asArray(input).map((m) => new TraceMap(m, ''));
13130
- const map = maps.pop();
13131
- for (let i = 0; i < maps.length; i++) {
13132
- if (maps[i].sources.length > 1) {
13133
- throw new Error(`Transformation map ${i} must have exactly one source file.\n` +
13134
- 'Did you specify these with the most recent transformation maps first?');
13135
- }
13136
- }
13137
- let tree = build(map, loader, '', 0);
13138
- for (let i = maps.length - 1; i >= 0; i--) {
13139
- tree = MapSource(maps[i], [tree]);
13140
- }
13141
- return tree;
13142
- }
13143
- function build(map, loader, importer, importerDepth) {
13144
- const { resolvedSources, sourcesContent } = map;
13145
- const depth = importerDepth + 1;
13146
- const children = resolvedSources.map((sourceFile, i) => {
13147
- // The loading context gives the loader more information about why this file is being loaded
13148
- // (eg, from which importer). It also allows the loader to override the location of the loaded
13149
- // sourcemap/original source, or to override the content in the sourcesContent field if it's
13150
- // an unmodified source file.
13151
- const ctx = {
13152
- importer,
13153
- depth,
13154
- source: sourceFile || '',
13155
- content: undefined,
13156
- };
13157
- // Use the provided loader callback to retrieve the file's sourcemap.
13158
- // TODO: We should eventually support async loading of sourcemap files.
13159
- const sourceMap = loader(ctx.source, ctx);
13160
- const { source, content } = ctx;
13161
- // If there is a sourcemap, then we need to recurse into it to load its source files.
13162
- if (sourceMap)
13163
- return build(new TraceMap(sourceMap, source), loader, source, depth);
13164
- // Else, it's an an unmodified source file.
13165
- // The contents of this unmodified source file can be overridden via the loader context,
13166
- // allowing it to be explicitly null or a string. If it remains undefined, we fall back to
13167
- // the importing sourcemap's `sourcesContent` field.
13168
- const sourceContent = content !== undefined ? content : sourcesContent ? sourcesContent[i] : null;
13169
- return OriginalSource(source, sourceContent);
13170
- });
13171
- return MapSource(map, children);
12833
+ function getCSSModuleProxyReturn(strategy, filename) {
12834
+ if (strategy === "non-scoped")
12835
+ return "style";
12836
+ const hash = generateCssFilenameHash(filename);
12837
+ return `\`_\${style}_${hash}\``;
13172
12838
  }
13173
-
13174
- /**
13175
- * A SourceMap v3 compatible sourcemap, which only includes fields that were
13176
- * provided to it.
13177
- */
13178
- class SourceMap {
13179
- constructor(map, options) {
13180
- const out = options.decodedMappings ? decodedMap(map) : encodedMap(map);
13181
- this.version = out.version; // SourceMap spec says this should be first.
13182
- this.file = out.file;
13183
- this.mappings = out.mappings;
13184
- this.names = out.names;
13185
- this.sourceRoot = out.sourceRoot;
13186
- this.sources = out.sources;
13187
- if (!options.excludeContent) {
13188
- this.sourcesContent = out.sourcesContent;
12839
+ function CSSEnablerPlugin(ctx) {
12840
+ const shouldProcessCSS = (id) => {
12841
+ const { css } = ctx.config;
12842
+ if (typeof css === "boolean")
12843
+ return css;
12844
+ if (toArray(css.exclude).some((re) => re.test(id)))
12845
+ return false;
12846
+ if (toArray(css.include).some((re) => re.test(id)))
12847
+ return true;
12848
+ return false;
12849
+ };
12850
+ return [
12851
+ {
12852
+ name: "vitest:css-disable",
12853
+ enforce: "pre",
12854
+ transform(code, id) {
12855
+ if (!isCSS(id))
12856
+ return;
12857
+ if (!shouldProcessCSS(id))
12858
+ return { code: "" };
12859
+ }
12860
+ },
12861
+ {
12862
+ name: "vitest:css-empty-post",
12863
+ enforce: "post",
12864
+ transform(_, id) {
12865
+ var _a;
12866
+ if (!isCSS(id) || shouldProcessCSS(id))
12867
+ return;
12868
+ if (isCSSModule(id)) {
12869
+ const scopeStrategy = typeof ctx.config.css !== "boolean" && ((_a = ctx.config.css.modules) == null ? void 0 : _a.classNameStrategy) || "stable";
12870
+ const proxyReturn = getCSSModuleProxyReturn(scopeStrategy, relative(ctx.config.root, id));
12871
+ const code = `export default new Proxy(Object.create(null), {
12872
+ get(_, style) {
12873
+ return ${proxyReturn};
12874
+ },
12875
+ })`;
12876
+ return { code };
13189
12877
  }
12878
+ return { code: 'export default ""' };
12879
+ }
13190
12880
  }
13191
- toString() {
13192
- return JSON.stringify(this);
13193
- }
12881
+ ];
13194
12882
  }
13195
12883
 
13196
- /**
13197
- * Traces through all the mappings in the root sourcemap, through the sources
13198
- * (and their sourcemaps), all the way back to the original source location.
13199
- *
13200
- * `loader` will be called every time we encounter a source file. If it returns
13201
- * a sourcemap, we will recurse into that sourcemap to continue the trace. If
13202
- * it returns a falsey value, that source file is treated as an original,
13203
- * unmodified source file.
13204
- *
13205
- * Pass `excludeContent` to exclude any self-containing source file content
13206
- * from the output sourcemap.
13207
- *
13208
- * Pass `decodedMappings` to receive a SourceMap with decoded (instead of
13209
- * VLQ encoded) mappings.
13210
- */
13211
- function remapping(input, loader, options) {
13212
- const opts = typeof options === 'object' ? options : { excludeContent: !!options, decodedMappings: false };
13213
- const tree = buildSourceMapTree(input, loader);
13214
- return new SourceMap(traceMappings(tree), opts);
12884
+ function EnvReplacerPlugin() {
12885
+ return {
12886
+ name: "vitest:env-replacer",
12887
+ enforce: "pre",
12888
+ transform(code, id) {
12889
+ if (!/\bimport\.meta\.env\b/g.test(code))
12890
+ return null;
12891
+ let s = null;
12892
+ const envs = stripLiteral(code).matchAll(/\bimport\.meta\.env\b/g);
12893
+ for (const env of envs) {
12894
+ s || (s = new MagicString(code));
12895
+ const startIndex = env.index;
12896
+ const endIndex = startIndex + env[0].length;
12897
+ s.overwrite(startIndex, endIndex, "process.env");
12898
+ }
12899
+ if (s) {
12900
+ return {
12901
+ code: s.toString(),
12902
+ map: s.generateMap({
12903
+ hires: true,
12904
+ // Remove possible query parameters, e.g. vue's "?vue&type=script&src=true&lang.ts"
12905
+ source: cleanUrl(id)
12906
+ })
12907
+ };
12908
+ }
12909
+ }
12910
+ };
13215
12911
  }
13216
12912
 
13217
- const hoistRegexp = /^[ \t]*\b(?:__vite_ssr_import_\d+__\.)?((?:vitest|vi)\s*.\s*(mock|unmock)\(["`'\s]+(.*[@\w_-]+)["`'\s]+)[),]{1};?/gm;
13218
- const API_NOT_FOUND_ERROR = `There are some problems in resolving the mocks API.
13219
- You may encounter this issue when importing the mocks API from another module other than 'vitest'.
13220
-
13221
- To fix this issue you can either:
13222
- - import the mocks API directly from 'vitest'
13223
- - enable the 'globals' options`;
13224
- function hoistModuleMocks(mod, vitestPath) {
13225
- if (!mod.code)
13226
- return mod;
13227
- const m = hoistCodeMocks(mod.code);
13228
- if (m) {
13229
- const vitestRegexp = new RegExp(`const __vite_ssr_import_\\d+__ = await __vite_ssr_import__\\("(?:/@fs/?)?(?:${vitestPath}|vitest)"\\);`, "gm");
13230
- const vitestImports = mod.code.matchAll(vitestRegexp);
13231
- let found = false;
13232
- for (const match of vitestImports) {
13233
- const indexStart = match.index;
13234
- const indexEnd = match[0].length + indexStart;
13235
- m.remove(indexStart, indexEnd);
13236
- m.prepend(`${match[0]}
13237
- `);
13238
- found = true;
13239
- }
13240
- if (!found) {
13241
- m.prepend(`if (typeof globalThis.vi === "undefined" && typeof globalThis.vitest === "undefined") { throw new Error(${JSON.stringify(API_NOT_FOUND_ERROR)}) }
13242
- `);
13243
- }
12913
+ async function loadGlobalSetupFiles(project) {
12914
+ var _a;
12915
+ const server = project.server;
12916
+ const runner = project.runner;
12917
+ const globalSetupFiles = toArray((_a = server.config.test) == null ? void 0 : _a.globalSetup);
12918
+ return Promise.all(globalSetupFiles.map((file) => loadGlobalSetupFile(file, runner)));
12919
+ }
12920
+ async function loadGlobalSetupFile(file, runner) {
12921
+ const m = await runner.executeFile(file);
12922
+ for (const exp of ["default", "setup", "teardown"]) {
12923
+ if (m[exp] != null && typeof m[exp] !== "function")
12924
+ throw new Error(`invalid export in globalSetup file ${file}: ${exp} must be a function`);
12925
+ }
12926
+ if (m.default) {
13244
12927
  return {
13245
- ...mod,
13246
- code: m.toString(),
13247
- map: mod.map ? combineSourcemaps(
13248
- mod.map.file,
13249
- [
13250
- {
13251
- ...m.generateMap({ hires: true }),
13252
- sourcesContent: mod.map.sourcesContent
13253
- },
13254
- mod.map
13255
- ]
13256
- ) : null
12928
+ file,
12929
+ setup: m.default
12930
+ };
12931
+ } else if (m.setup || m.teardown) {
12932
+ return {
12933
+ file,
12934
+ setup: m.setup,
12935
+ teardown: m.teardown
13257
12936
  };
13258
- }
13259
- return mod;
13260
- }
13261
- function hoistCodeMocks(code) {
13262
- let m;
13263
- const mocks = code.matchAll(hoistRegexp);
13264
- for (const mockResult of mocks) {
13265
- const lastIndex = getMockLastIndex(code.slice(mockResult.index));
13266
- if (lastIndex === null)
13267
- continue;
13268
- const startIndex = mockResult.index;
13269
- const { insideComment, insideString } = getIndexStatus(code, startIndex);
13270
- if (insideComment || insideString)
13271
- continue;
13272
- const endIndex = startIndex + lastIndex;
13273
- m ?? (m = new MagicString(code));
13274
- m.prepend(`${m.slice(startIndex, endIndex)}
13275
- `);
13276
- m.remove(startIndex, endIndex);
13277
- }
13278
- return m;
13279
- }
13280
- function escapeToLinuxLikePath(path) {
13281
- if (/^[A-Z]:/.test(path))
13282
- return path.replace(/^([A-Z]):\//, "/windows/$1/");
13283
- if (/^\/[^/]/.test(path))
13284
- return `/linux${path}`;
13285
- return path;
13286
- }
13287
- function unescapeToLinuxLikePath(path) {
13288
- if (path.startsWith("/linux/"))
13289
- return path.slice("/linux".length);
13290
- if (path.startsWith("/windows/"))
13291
- return path.replace(/^\/windows\/([A-Z])\//, "$1:/");
13292
- return path;
13293
- }
13294
- const nullSourceMap = {
13295
- names: [],
13296
- sources: [],
13297
- mappings: "",
13298
- version: 3
13299
- };
13300
- function combineSourcemaps(filename, sourcemapList, excludeContent = true) {
13301
- if (sourcemapList.length === 0 || sourcemapList.every((m) => m.sources.length === 0))
13302
- return { ...nullSourceMap };
13303
- sourcemapList = sourcemapList.map((sourcemap) => {
13304
- const newSourcemaps = { ...sourcemap };
13305
- newSourcemaps.sources = sourcemap.sources.map(
13306
- (source) => source ? escapeToLinuxLikePath(source) : null
13307
- );
13308
- if (sourcemap.sourceRoot)
13309
- newSourcemaps.sourceRoot = escapeToLinuxLikePath(sourcemap.sourceRoot);
13310
- return newSourcemaps;
13311
- });
13312
- const escapedFilename = escapeToLinuxLikePath(filename);
13313
- let map;
13314
- let mapIndex = 1;
13315
- const useArrayInterface = sourcemapList.slice(0, -1).find((m) => m.sources.length !== 1) === void 0;
13316
- if (useArrayInterface) {
13317
- map = remapping(sourcemapList, () => null, excludeContent);
13318
12937
  } else {
13319
- map = remapping(
13320
- sourcemapList[0],
13321
- (sourcefile) => {
13322
- if (sourcefile === escapedFilename && sourcemapList[mapIndex])
13323
- return sourcemapList[mapIndex++];
13324
- else
13325
- return null;
13326
- },
13327
- excludeContent
13328
- );
12938
+ throw new Error(`invalid globalSetup file ${file}. Must export setup, teardown or have a default export`);
13329
12939
  }
13330
- if (!map.file)
13331
- delete map.file;
13332
- map.sources = map.sources.map(
13333
- (source) => source ? unescapeToLinuxLikePath(source) : source
13334
- );
13335
- map.file = filename;
13336
- return map;
13337
- }
13338
- function getMockLastIndex(code) {
13339
- const index = getCallLastIndex(code);
13340
- if (index === null)
13341
- return null;
13342
- return code[index + 1] === ";" ? index + 2 : index + 1;
13343
12940
  }
13344
- function getIndexStatus(code, from) {
13345
- let index = 0;
13346
- let commentStarted = false;
13347
- let commentEnded = true;
13348
- let multilineCommentStarted = false;
13349
- let multilineCommentEnded = true;
13350
- let inString = null;
13351
- let beforeChar = null;
13352
- while (index <= from) {
13353
- const char = code[index];
13354
- const sub = code[index] + code[index + 1];
13355
- if (!inString) {
13356
- if (sub === "/*") {
13357
- multilineCommentStarted = true;
13358
- multilineCommentEnded = false;
13359
- }
13360
- if (sub === "*/" && multilineCommentStarted) {
13361
- multilineCommentStarted = false;
13362
- multilineCommentEnded = true;
13363
- }
13364
- if (sub === "//") {
13365
- commentStarted = true;
13366
- commentEnded = false;
13367
- }
13368
- if ((char === "\n" || sub === "\r\n") && commentStarted) {
13369
- commentStarted = false;
13370
- commentEnded = true;
12941
+ function GlobalSetupPlugin(project, logger) {
12942
+ let globalSetupFiles;
12943
+ return {
12944
+ name: "vitest:global-setup-plugin",
12945
+ enforce: "pre",
12946
+ async buildStart() {
12947
+ var _a, _b;
12948
+ if (!((_a = project.server.config.test) == null ? void 0 : _a.globalSetup))
12949
+ return;
12950
+ globalSetupFiles = await loadGlobalSetupFiles(project);
12951
+ try {
12952
+ for (const globalSetupFile of globalSetupFiles) {
12953
+ const teardown = await ((_b = globalSetupFile.setup) == null ? void 0 : _b.call(globalSetupFile));
12954
+ if (teardown == null || !!globalSetupFile.teardown)
12955
+ continue;
12956
+ if (typeof teardown !== "function")
12957
+ throw new Error(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`);
12958
+ globalSetupFile.teardown = teardown;
12959
+ }
12960
+ } catch (e) {
12961
+ logger.error(`
12962
+ ${c.red(divider(c.bold(c.inverse(" Error during global setup "))))}`);
12963
+ await logger.printError(e);
12964
+ process.exit(1);
13371
12965
  }
13372
- }
13373
- if (!multilineCommentStarted && !commentStarted) {
13374
- const isCharString = char === '"' || char === "'" || char === "`";
13375
- if (isCharString && beforeChar !== "\\") {
13376
- if (inString === char)
13377
- inString = null;
13378
- else if (!inString)
13379
- inString = char;
12966
+ },
12967
+ async buildEnd() {
12968
+ var _a;
12969
+ if (globalSetupFiles == null ? void 0 : globalSetupFiles.length) {
12970
+ for (const globalSetupFile of globalSetupFiles.reverse()) {
12971
+ try {
12972
+ await ((_a = globalSetupFile.teardown) == null ? void 0 : _a.call(globalSetupFile));
12973
+ } catch (error) {
12974
+ logger.error(`error during global teardown of ${globalSetupFile.file}`, error);
12975
+ }
12976
+ }
13380
12977
  }
13381
12978
  }
13382
- beforeChar = char;
13383
- index++;
13384
- }
13385
- return {
13386
- insideComment: !multilineCommentEnded || !commentEnded,
13387
- insideString: inString !== null
13388
12979
  };
13389
12980
  }
13390
12981
 
13391
- class VitestServer extends ViteNodeServer {
13392
- async getVitestPath() {
13393
- if (!this._vitestPath) {
13394
- const { id } = await this.resolveId("vitest") || { id: "vitest" };
13395
- this._vitestPath = id;
13396
- }
13397
- return this._vitestPath;
13398
- }
13399
- async processTransformResult(id, result) {
13400
- const vitestId = await this.getVitestPath();
13401
- return super.processTransformResult(id, hoistModuleMocks(result, vitestId));
13402
- }
12982
+ function WorkspaceVitestPlugin(project, options) {
12983
+ return [
12984
+ {
12985
+ name: "vitest:project",
12986
+ enforce: "pre",
12987
+ options() {
12988
+ this.meta.watchMode = false;
12989
+ },
12990
+ // TODO: refactor so we don't have the same code here and in plugins/index.ts
12991
+ config(viteConfig) {
12992
+ var _a, _b, _c;
12993
+ if (viteConfig.define) {
12994
+ delete viteConfig.define["import.meta.vitest"];
12995
+ delete viteConfig.define["process.env"];
12996
+ }
12997
+ const env = {};
12998
+ for (const key in viteConfig.define) {
12999
+ const val = viteConfig.define[key];
13000
+ let replacement;
13001
+ try {
13002
+ replacement = typeof val === "string" ? JSON.parse(val) : val;
13003
+ } catch {
13004
+ continue;
13005
+ }
13006
+ if (key.startsWith("import.meta.env.")) {
13007
+ const envKey = key.slice("import.meta.env.".length);
13008
+ env[envKey] = replacement;
13009
+ delete viteConfig.define[key];
13010
+ } else if (key.startsWith("process.env.")) {
13011
+ const envKey = key.slice("process.env.".length);
13012
+ env[envKey] = replacement;
13013
+ delete viteConfig.define[key];
13014
+ }
13015
+ }
13016
+ const testConfig = viteConfig.test || {};
13017
+ const root = testConfig.root || viteConfig.root || options.root;
13018
+ let name = testConfig.name;
13019
+ if (!name) {
13020
+ if (typeof options.workspacePath === "string")
13021
+ name = dirname(options.workspacePath).split("/").pop();
13022
+ else
13023
+ name = options.workspacePath.toString();
13024
+ }
13025
+ const config = {
13026
+ root,
13027
+ resolve: {
13028
+ // by default Vite resolves `module` field, which not always a native ESM module
13029
+ // setting this option can bypass that and fallback to cjs version
13030
+ mainFields: [],
13031
+ alias: testConfig.alias,
13032
+ conditions: ["node"],
13033
+ // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
13034
+ // @ts-ignore we support Vite ^3.0, but browserField is available in Vite ^3.2
13035
+ browserField: false
13036
+ },
13037
+ esbuild: {
13038
+ sourcemap: "external",
13039
+ // Enables using ignore hint for coverage providers with @preserve keyword
13040
+ legalComments: "inline"
13041
+ },
13042
+ server: {
13043
+ // disable watch mode in workspaces,
13044
+ // because it is handled by the top-level watcher
13045
+ watch: {
13046
+ ignored: ["**/*"],
13047
+ depth: 0,
13048
+ persistent: false
13049
+ },
13050
+ open: false,
13051
+ hmr: false,
13052
+ preTransformRequests: false
13053
+ },
13054
+ test: {
13055
+ env,
13056
+ name
13057
+ }
13058
+ };
13059
+ const classNameStrategy = typeof testConfig.css !== "boolean" && ((_b = (_a = testConfig.css) == null ? void 0 : _a.modules) == null ? void 0 : _b.classNameStrategy) || "stable";
13060
+ if (classNameStrategy !== "scoped") {
13061
+ config.css ?? (config.css = {});
13062
+ (_c = config.css).modules ?? (_c.modules = {});
13063
+ if (config.css.modules) {
13064
+ config.css.modules.generateScopedName = (name2, filename) => {
13065
+ const root2 = project.config.root;
13066
+ return generateScopedClassName(classNameStrategy, name2, relative(root2, filename));
13067
+ };
13068
+ }
13069
+ }
13070
+ return config;
13071
+ },
13072
+ async configureServer(server) {
13073
+ try {
13074
+ const options2 = deepMerge(
13075
+ {},
13076
+ configDefaults,
13077
+ server.config.test || {}
13078
+ );
13079
+ await project.setServer(options2, server);
13080
+ } catch (err) {
13081
+ await project.ctx.logger.printError(err, true);
13082
+ process.exit(1);
13083
+ }
13084
+ await server.watcher.close();
13085
+ }
13086
+ },
13087
+ EnvReplacerPlugin(),
13088
+ ...CSSEnablerPlugin(project),
13089
+ CoverageTransform(project.ctx),
13090
+ GlobalSetupPlugin(project, project.ctx.logger),
13091
+ MocksPlugin()
13092
+ ];
13403
13093
  }
13404
13094
 
13405
13095
  async function initializeProject(workspacePath, ctx, options) {
@@ -13454,7 +13144,7 @@ class WorkspaceProject {
13454
13144
  await Promise.all(files.map(async (file) => {
13455
13145
  try {
13456
13146
  const code = await promises.readFile(file, "utf-8");
13457
- if (this.ctx.isInSourceTestFile(code))
13147
+ if (this.isInSourceTestFile(code))
13458
13148
  testFiles.push(file);
13459
13149
  } catch {
13460
13150
  return null;
@@ -13472,6 +13162,22 @@ class WorkspaceProject {
13472
13162
  };
13473
13163
  return out(include, globOptions);
13474
13164
  }
13165
+ async isTargetFile(id, source) {
13166
+ var _a;
13167
+ const relativeId = relative(this.config.dir || this.config.root, id);
13168
+ if (micromatch_1.isMatch(relativeId, this.config.exclude))
13169
+ return false;
13170
+ if (micromatch_1.isMatch(relativeId, this.config.include))
13171
+ return true;
13172
+ if (((_a = this.config.includeSource) == null ? void 0 : _a.length) && micromatch_1.isMatch(relativeId, this.config.includeSource)) {
13173
+ source = source || await promises.readFile(id, "utf-8");
13174
+ return this.isInSourceTestFile(source);
13175
+ }
13176
+ return false;
13177
+ }
13178
+ isInSourceTestFile(code) {
13179
+ return code.includes("import.meta.vitest");
13180
+ }
13475
13181
  filterFiles(testFiles, filters = []) {
13476
13182
  if (filters.length && process.platform === "win32")
13477
13183
  filters = filters.map((f) => toNamespacedPath(f));
@@ -13489,7 +13195,7 @@ class WorkspaceProject {
13489
13195
  async setServer(options, server, params = {}) {
13490
13196
  this.config = resolveConfig(this.ctx.mode, options, server.config);
13491
13197
  this.server = server;
13492
- this.vitenode = params.server ?? new VitestServer(server, this.config);
13198
+ this.vitenode = params.server ?? new ViteNodeServer(server, this.config);
13493
13199
  const node = this.vitenode;
13494
13200
  this.runner = params.runner ?? new ViteNodeRunner({
13495
13201
  root: server.config.root,
@@ -13631,6 +13337,7 @@ class Vitest {
13631
13337
  this.vitenode = void 0;
13632
13338
  this.invalidates = /* @__PURE__ */ new Set();
13633
13339
  this.changedTests = /* @__PURE__ */ new Set();
13340
+ this.isCancelling = false;
13634
13341
  this.isFirstRun = true;
13635
13342
  this.restartsCount = 0;
13636
13343
  this.runner = void 0;
@@ -13638,6 +13345,7 @@ class Vitest {
13638
13345
  this.projectsTestFiles = /* @__PURE__ */ new Map();
13639
13346
  this._onRestartListeners = [];
13640
13347
  this._onSetServer = [];
13348
+ this._onCancelListeners = [];
13641
13349
  this.unregisterWatcher = noop$1;
13642
13350
  this.logger = new Logger(this);
13643
13351
  }
@@ -13650,6 +13358,7 @@ class Vitest {
13650
13358
  this.pool = void 0;
13651
13359
  this.coverageProvider = void 0;
13652
13360
  this.runningPromise = void 0;
13361
+ this.projectsTestFiles.clear();
13653
13362
  const resolved = resolveConfig(this.mode, options, server.config);
13654
13363
  this.server = server;
13655
13364
  this.config = resolved;
@@ -13658,7 +13367,7 @@ class Vitest {
13658
13367
  this.snapshot = new SnapshotManager({ ...resolved.snapshotOptions });
13659
13368
  if (this.config.watch && this.mode !== "typecheck")
13660
13369
  this.registerWatcher();
13661
- this.vitenode = new VitestServer(server, this.config);
13370
+ this.vitenode = new ViteNodeServer(server, this.config);
13662
13371
  const node = this.vitenode;
13663
13372
  this.runner = new ViteNodeRunner({
13664
13373
  root: server.config.root,
@@ -13706,9 +13415,7 @@ class Vitest {
13706
13415
  return coreWorkspace;
13707
13416
  }
13708
13417
  getCoreWorkspaceProject() {
13709
- if (!this.coreWorkspace)
13710
- throw new Error("Core workspace project is not initialized");
13711
- return this.coreWorkspace;
13418
+ return this.coreWorkspace || null;
13712
13419
  }
13713
13420
  async resolveWorkspace(options, cliOptions) {
13714
13421
  const configDir = this.server.config.configFile ? dirname(this.server.config.configFile) : this.config.root;
@@ -13814,15 +13521,10 @@ class Vitest {
13814
13521
  await this.typecheck(filters);
13815
13522
  return;
13816
13523
  }
13817
- try {
13818
- await this.initCoverageProvider();
13819
- await ((_a = this.coverageProvider) == null ? void 0 : _a.clean(this.config.coverage.clean));
13820
- await this.initBrowserProviders();
13821
- } catch (e) {
13822
- this.logger.error(e);
13823
- process.exit(1);
13824
- }
13825
13524
  await this.report("onInit", this);
13525
+ await this.initCoverageProvider();
13526
+ await ((_a = this.coverageProvider) == null ? void 0 : _a.clean(this.config.coverage.clean));
13527
+ await this.initBrowserProviders();
13826
13528
  const files = await this.filterTestsBySource(
13827
13529
  await this.globTestFiles(filters)
13828
13530
  );
@@ -13902,6 +13604,8 @@ class Vitest {
13902
13604
  this.state.collectPaths(filepaths);
13903
13605
  await this.report("onPathsCollected", filepaths);
13904
13606
  await this.runningPromise;
13607
+ this._onCancelListeners = [];
13608
+ this.isCancelling = false;
13905
13609
  this.runningPromise = (async () => {
13906
13610
  if (!this.pool)
13907
13611
  this.pool = createPool(this);
@@ -13926,6 +13630,10 @@ class Vitest {
13926
13630
  });
13927
13631
  return await this.runningPromise;
13928
13632
  }
13633
+ async cancelCurrentRun(reason) {
13634
+ this.isCancelling = true;
13635
+ await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason)));
13636
+ }
13929
13637
  async rerunFiles(files = this.state.getFilepaths(), trigger) {
13930
13638
  if (this.filenamePattern) {
13931
13639
  const filteredFiles = await this.globTestFiles([this.filenamePattern]);
@@ -14039,7 +13747,13 @@ class Vitest {
14039
13747
  const onAdd = async (id) => {
14040
13748
  id = slash$1(id);
14041
13749
  updateLastChanged(id);
14042
- if (await this.isTargetFile(id)) {
13750
+ const matchingProjects = [];
13751
+ await Promise.all(this.projects.map(async (project) => {
13752
+ if (await project.isTargetFile(id))
13753
+ matchingProjects.push(project);
13754
+ }));
13755
+ if (matchingProjects.length > 0) {
13756
+ this.projectsTestFiles.set(id, new Set(matchingProjects));
14043
13757
  this.changedTests.add(id);
14044
13758
  this.scheduleRerun([id]);
14045
13759
  }
@@ -14116,10 +13830,12 @@ class Vitest {
14116
13830
  async close() {
14117
13831
  var _a;
14118
13832
  if (!this.closingPromise) {
13833
+ const closePromises = this.projects.map((w) => w.close());
13834
+ if (this.coreWorkspace && !this.projects.includes(this.coreWorkspace))
13835
+ closePromises.push(this.server.close());
14119
13836
  this.closingPromise = Promise.allSettled([
14120
13837
  (_a = this.pool) == null ? void 0 : _a.close(),
14121
- this.server.close(),
14122
- ...this.projects.map((w) => w.close())
13838
+ ...closePromises
14123
13839
  ].filter(Boolean)).then((results) => {
14124
13840
  results.filter((r) => r.status === "rejected").forEach((err) => {
14125
13841
  this.logger.error("error during close", err.reason);
@@ -14165,33 +13881,20 @@ class Vitest {
14165
13881
  }));
14166
13882
  return files;
14167
13883
  }
14168
- async isTargetFile(id, source) {
14169
- var _a;
14170
- const relativeId = relative(this.config.dir || this.config.root, id);
14171
- if (micromatch_1.isMatch(relativeId, this.config.exclude))
14172
- return false;
14173
- if (micromatch_1.isMatch(relativeId, this.config.include))
14174
- return true;
14175
- if (((_a = this.config.includeSource) == null ? void 0 : _a.length) && micromatch_1.isMatch(relativeId, this.config.includeSource)) {
14176
- source = source || await promises.readFile(id, "utf-8");
14177
- return this.isInSourceTestFile(source);
14178
- }
14179
- return false;
14180
- }
14181
13884
  // The server needs to be running for communication
14182
13885
  shouldKeepServer() {
14183
13886
  var _a;
14184
13887
  return !!((_a = this.config) == null ? void 0 : _a.watch);
14185
13888
  }
14186
- isInSourceTestFile(code) {
14187
- return code.includes("import.meta.vitest");
14188
- }
14189
13889
  onServerRestart(fn) {
14190
13890
  this._onRestartListeners.push(fn);
14191
13891
  }
14192
13892
  onAfterSetServer(fn) {
14193
13893
  this._onSetServer.push(fn);
14194
13894
  }
13895
+ onCancel(fn) {
13896
+ this._onCancelListeners.push(fn);
13897
+ }
14195
13898
  }
14196
13899
 
14197
13900
  async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
@@ -14202,7 +13905,7 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
14202
13905
  };
14203
13906
  async function UIPlugin() {
14204
13907
  await ensurePackageInstalled("@vitest/ui", getRoot());
14205
- return (await import('@vitest/ui')).default(options.uiBase);
13908
+ return (await import('@vitest/ui')).default(ctx);
14206
13909
  }
14207
13910
  return [
14208
13911
  {
@@ -14333,7 +14036,7 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
14333
14036
  try {
14334
14037
  await ctx.setServer(options, server, userConfig);
14335
14038
  if (options.api && options.watch)
14336
- (await import('./chunk-api-setup.c93e5069.js')).setup(ctx);
14039
+ (await import('./chunk-api-setup.df3106cd.js')).setup(ctx);
14337
14040
  } catch (err) {
14338
14041
  await ctx.logger.printError(err, true);
14339
14042
  process.exit(1);
@@ -14346,7 +14049,8 @@ async function VitestPlugin(options = {}, ctx = new Vitest("test")) {
14346
14049
  GlobalSetupPlugin(ctx, ctx.logger),
14347
14050
  ...CSSEnablerPlugin(ctx),
14348
14051
  CoverageTransform(ctx),
14349
- options.ui ? await UIPlugin() : null
14052
+ options.ui ? await UIPlugin() : null,
14053
+ MocksPlugin()
14350
14054
  ].filter(notNullish);
14351
14055
  }
14352
14056
 
@@ -20650,6 +20354,7 @@ const keys = [
20650
20354
  ["t", "filter by a test name regex pattern"],
20651
20355
  ["q", "quit"]
20652
20356
  ];
20357
+ const cancelKeys = ["space", "c", ...keys.map((key) => key[0])];
20653
20358
  function printShortcutsHelp() {
20654
20359
  stdout().write(
20655
20360
  `
@@ -20668,9 +20373,12 @@ function registerConsoleShortcuts(ctx) {
20668
20373
  process.kill(process.pid, "SIGTSTP");
20669
20374
  return;
20670
20375
  }
20671
- if (ctx.runningPromise)
20672
- return;
20673
20376
  const name = key == null ? void 0 : key.name;
20377
+ if (ctx.runningPromise) {
20378
+ if (cancelKeys.includes(name))
20379
+ await ctx.cancelCurrentRun("keyboard-input");
20380
+ return;
20381
+ }
20674
20382
  if (name === "q")
20675
20383
  return ctx.exit(true);
20676
20384
  if (ctx.mode === "typecheck")
@@ -20700,8 +20408,8 @@ function registerConsoleShortcuts(ctx) {
20700
20408
  message: "Input test name pattern (RegExp)",
20701
20409
  initial: ((_a = ctx.configOverride.testNamePattern) == null ? void 0 : _a.source) || ""
20702
20410
  }]);
20703
- await ctx.changeNamePattern(filter.trim(), void 0, "change pattern");
20704
20411
  on();
20412
+ await ctx.changeNamePattern(filter.trim(), void 0, "change pattern");
20705
20413
  }
20706
20414
  async function inputFilePattern() {
20707
20415
  off();
@@ -20712,8 +20420,8 @@ function registerConsoleShortcuts(ctx) {
20712
20420
  initial: latestFilename
20713
20421
  }]);
20714
20422
  latestFilename = filter.trim();
20715
- await ctx.changeFilenamePattern(filter.trim());
20716
20423
  on();
20424
+ await ctx.changeFilenamePattern(filter.trim());
20717
20425
  }
20718
20426
  let rl;
20719
20427
  function on() {