import { existsSync, promises, readFileSync, mkdirSync, writeFileSync } from 'node:fs'; import { createFileTask, limitConcurrency, getTasks, hasFailed, getTests, getNames } from '@vitest/runner/utils'; import { normalize, relative, dirname, resolve, join, basename, isAbsolute } from 'pathe'; import { g as getCoverageProvider, C as CoverageProviderMap } from './coverage.BoMDb1ip.js'; import a, { resolve as resolve$1 } from 'node:path'; import { noop, isPrimitive, toArray, deepMerge, nanoid, slash, notNullish, createDefer } from '@vitest/utils'; import { f as findUp, p as prompt } from './index.BJDntFik.js'; import { searchForWorkspaceRoot, version, createServer, mergeConfig } from 'vite'; import { A as API_PATH, c as configFiles, a as defaultBrowserPort, w as workspacesFiles, d as defaultPort } from './constants.fzPh7AOq.js'; import { SnapshotManager } from '@vitest/snapshot/manager'; import { i as isPackageExists, e as requireMicromatch, V as VitestCache, f as configDefaults, m as mm, b as resolveConfig, h as isBrowserEnabled, w as wildcardPatternToRegExp, g as getFilePoolName, j as createPool, a as resolveApiServerConfig, c as coverageConfigDefaults, s as stdout } from './resolveConfig.rBxzbVsl.js'; import { ViteNodeRunner } from 'vite-node/client'; import { ViteNodeServer } from 'vite-node/server'; import { v as version$1 } from './cac.CB_9Zo9Q.js'; import { c as createBirpc } from './index.68735LiX.js'; import { s as stringify, p as parse, R as ReportersMap, h as BenchmarkReportsMap, f as TestModule, g as TestSuite, e as TestCase, j as generateCodeFrame, i as TestProject, L as Logger, k as BlobReporter, r as readBlobs } from './index.DsZFoqi9.js'; import require$$0$2 from 'stream'; import require$$0 from 'zlib'; import require$$0$1 from 'buffer'; import require$$1 from 'crypto'; import require$$0$3 from 'events'; import require$$1$1 from 'https'; import require$$2 from 'http'; import require$$3 from 'net'; import require$$4 from 'tls'; import require$$7 from 'url'; import { g as getDefaultExportFromCjs, c as commonjsGlobal } from './_commonjsHelpers.BFTU3MAI.js'; import { parseErrorStacktrace } from '@vitest/utils/source-map'; import crypto from 'node:crypto'; import { distDir, rootDir } from '../path.js'; import { createRequire } from 'node:module'; import url from 'node:url'; import c from 'tinyrainbow'; import { h as hash, i as isWindows } from './RandomSequencer.CMRlh2v4.js'; import { isCI } from 'std-env'; import { rm } from 'node:fs/promises'; import nodeos__default, { tmpdir } from 'node:os'; import require$$0$4 from 'os'; import require$$0$5 from 'path'; import require$$0$6 from 'fs'; import { normalizeRequestId, cleanUrl } from 'vite-node/utils'; import { hoistMocksPlugin, automockPlugin } from '@vitest/mocker/node'; import MagicString from 'magic-string'; import readline from 'node:readline'; import { stripVTControlCharacters } from 'node:util'; function isValidApiRequest(config, req) { const url = new URL(req.url ?? "", "http://localhost"); try { const token = url.searchParams.get("token"); if (token && crypto.timingSafeEqual( Buffer.from(token), Buffer.from(config.api.token) )) { return true; } } catch { } return false; } var bufferUtil = {exports: {}}; var constants$1; var hasRequiredConstants$1; function requireConstants$1 () { if (hasRequiredConstants$1) return constants$1; hasRequiredConstants$1 = 1; const BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments']; const hasBlob = typeof Blob !== 'undefined'; if (hasBlob) BINARY_TYPES.push('blob'); constants$1 = { BINARY_TYPES, EMPTY_BUFFER: Buffer.alloc(0), GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', hasBlob, kForOnEventAttribute: Symbol('kIsForOnEventAttribute'), kListener: Symbol('kListener'), kStatusCode: Symbol('status-code'), kWebSocket: Symbol('websocket'), NOOP: () => {} }; return constants$1; } var hasRequiredBufferUtil; function requireBufferUtil () { if (hasRequiredBufferUtil) return bufferUtil.exports; hasRequiredBufferUtil = 1; const { EMPTY_BUFFER } = requireConstants$1(); const FastBuffer = Buffer[Symbol.species]; /** * Merges an array of buffers into a new buffer. * * @param {Buffer[]} list The array of buffers to concat * @param {Number} totalLength The total length of buffers in the list * @return {Buffer} The resulting buffer * @public */ function concat(list, totalLength) { if (list.length === 0) return EMPTY_BUFFER; if (list.length === 1) return list[0]; const target = Buffer.allocUnsafe(totalLength); let offset = 0; for (let i = 0; i < list.length; i++) { const buf = list[i]; target.set(buf, offset); offset += buf.length; } if (offset < totalLength) { return new FastBuffer(target.buffer, target.byteOffset, offset); } return target; } /** * Masks a buffer using the given mask. * * @param {Buffer} source The buffer to mask * @param {Buffer} mask The mask to use * @param {Buffer} output The buffer where to store the result * @param {Number} offset The offset at which to start writing * @param {Number} length The number of bytes to mask. * @public */ function _mask(source, mask, output, offset, length) { for (let i = 0; i < length; i++) { output[offset + i] = source[i] ^ mask[i & 3]; } } /** * Unmasks a buffer using the given mask. * * @param {Buffer} buffer The buffer to unmask * @param {Buffer} mask The mask to use * @public */ function _unmask(buffer, mask) { for (let i = 0; i < buffer.length; i++) { buffer[i] ^= mask[i & 3]; } } /** * Converts a buffer to an `ArrayBuffer`. * * @param {Buffer} buf The buffer to convert * @return {ArrayBuffer} Converted buffer * @public */ function toArrayBuffer(buf) { if (buf.length === buf.buffer.byteLength) { return buf.buffer; } return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length); } /** * Converts `data` to a `Buffer`. * * @param {*} data The data to convert * @return {Buffer} The buffer * @throws {TypeError} * @public */ function toBuffer(data) { toBuffer.readOnly = true; if (Buffer.isBuffer(data)) return data; let buf; if (data instanceof ArrayBuffer) { buf = new FastBuffer(data); } else if (ArrayBuffer.isView(data)) { buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength); } else { buf = Buffer.from(data); toBuffer.readOnly = false; } return buf; } bufferUtil.exports = { concat, mask: _mask, toArrayBuffer, toBuffer, unmask: _unmask }; /* istanbul ignore else */ if (!process.env.WS_NO_BUFFER_UTIL) { try { const bufferUtil$1 = require('bufferutil'); bufferUtil.exports.mask = function (source, mask, output, offset, length) { if (length < 48) _mask(source, mask, output, offset, length); else bufferUtil$1.mask(source, mask, output, offset, length); }; bufferUtil.exports.unmask = function (buffer, mask) { if (buffer.length < 32) _unmask(buffer, mask); else bufferUtil$1.unmask(buffer, mask); }; } catch (e) { // Continue regardless of the error. } } return bufferUtil.exports; } var limiter; var hasRequiredLimiter; function requireLimiter () { if (hasRequiredLimiter) return limiter; hasRequiredLimiter = 1; const kDone = Symbol('kDone'); const kRun = Symbol('kRun'); /** * A very simple job queue with adjustable concurrency. Adapted from * https://github.com/STRML/async-limiter */ class Limiter { /** * Creates a new `Limiter`. * * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed * to run concurrently */ constructor(concurrency) { this[kDone] = () => { this.pending--; this[kRun](); }; this.concurrency = concurrency || Infinity; this.jobs = []; this.pending = 0; } /** * Adds a job to the queue. * * @param {Function} job The job to run * @public */ add(job) { this.jobs.push(job); this[kRun](); } /** * Removes a job from the queue and runs it if possible. * * @private */ [kRun]() { if (this.pending === this.concurrency) return; if (this.jobs.length) { const job = this.jobs.shift(); this.pending++; job(this[kDone]); } } } limiter = Limiter; return limiter; } var permessageDeflate; var hasRequiredPermessageDeflate; function requirePermessageDeflate () { if (hasRequiredPermessageDeflate) return permessageDeflate; hasRequiredPermessageDeflate = 1; const zlib = require$$0; const bufferUtil = requireBufferUtil(); const Limiter = requireLimiter(); const { kStatusCode } = requireConstants$1(); const FastBuffer = Buffer[Symbol.species]; const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); const kPerMessageDeflate = Symbol('permessage-deflate'); const kTotalLength = Symbol('total-length'); const kCallback = Symbol('callback'); const kBuffers = Symbol('buffers'); const kError = Symbol('error'); // // We limit zlib concurrency, which prevents severe memory fragmentation // as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913 // and https://github.com/websockets/ws/issues/1202 // // Intentionally global; it's the global thread pool that's an issue. // let zlibLimiter; /** * permessage-deflate implementation. */ class PerMessageDeflate { /** * Creates a PerMessageDeflate instance. * * @param {Object} [options] Configuration options * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support * for, or request, a custom client window size * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ * acknowledge disabling of client context takeover * @param {Number} [options.concurrencyLimit=10] The number of concurrent * calls to zlib * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the * use of a custom server window size * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept * disabling of server context takeover * @param {Number} [options.threshold=1024] Size (in bytes) below which * messages should not be compressed if context takeover is disabled * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on * deflate * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on * inflate * @param {Boolean} [isServer=false] Create the instance in either server or * client mode * @param {Number} [maxPayload=0] The maximum allowed message length */ constructor(options, isServer, maxPayload) { this._maxPayload = maxPayload | 0; this._options = options || {}; this._threshold = this._options.threshold !== undefined ? this._options.threshold : 1024; this._isServer = !!isServer; this._deflate = null; this._inflate = null; this.params = null; if (!zlibLimiter) { const concurrency = this._options.concurrencyLimit !== undefined ? this._options.concurrencyLimit : 10; zlibLimiter = new Limiter(concurrency); } } /** * @type {String} */ static get extensionName() { return 'permessage-deflate'; } /** * Create an extension negotiation offer. * * @return {Object} Extension parameters * @public */ offer() { const params = {}; if (this._options.serverNoContextTakeover) { params.server_no_context_takeover = true; } if (this._options.clientNoContextTakeover) { params.client_no_context_takeover = true; } if (this._options.serverMaxWindowBits) { params.server_max_window_bits = this._options.serverMaxWindowBits; } if (this._options.clientMaxWindowBits) { params.client_max_window_bits = this._options.clientMaxWindowBits; } else if (this._options.clientMaxWindowBits == null) { params.client_max_window_bits = true; } return params; } /** * Accept an extension negotiation offer/response. * * @param {Array} configurations The extension negotiation offers/reponse * @return {Object} Accepted configuration * @public */ accept(configurations) { configurations = this.normalizeParams(configurations); this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); return this.params; } /** * Releases all resources used by the extension. * * @public */ cleanup() { if (this._inflate) { this._inflate.close(); this._inflate = null; } if (this._deflate) { const callback = this._deflate[kCallback]; this._deflate.close(); this._deflate = null; if (callback) { callback( new Error( 'The deflate stream was closed while data was being processed' ) ); } } } /** * Accept an extension negotiation offer. * * @param {Array} offers The extension negotiation offers * @return {Object} Accepted configuration * @private */ acceptAsServer(offers) { const opts = this._options; const accepted = offers.find((params) => { if ( (opts.serverNoContextTakeover === false && params.server_no_context_takeover) || (params.server_max_window_bits && (opts.serverMaxWindowBits === false || (typeof opts.serverMaxWindowBits === 'number' && opts.serverMaxWindowBits > params.server_max_window_bits))) || (typeof opts.clientMaxWindowBits === 'number' && !params.client_max_window_bits) ) { return false; } return true; }); if (!accepted) { throw new Error('None of the extension offers can be accepted'); } if (opts.serverNoContextTakeover) { accepted.server_no_context_takeover = true; } if (opts.clientNoContextTakeover) { accepted.client_no_context_takeover = true; } if (typeof opts.serverMaxWindowBits === 'number') { accepted.server_max_window_bits = opts.serverMaxWindowBits; } if (typeof opts.clientMaxWindowBits === 'number') { accepted.client_max_window_bits = opts.clientMaxWindowBits; } else if ( accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false ) { delete accepted.client_max_window_bits; } return accepted; } /** * Accept the extension negotiation response. * * @param {Array} response The extension negotiation response * @return {Object} Accepted configuration * @private */ acceptAsClient(response) { const params = response[0]; if ( this._options.clientNoContextTakeover === false && params.client_no_context_takeover ) { throw new Error('Unexpected parameter "client_no_context_takeover"'); } if (!params.client_max_window_bits) { if (typeof this._options.clientMaxWindowBits === 'number') { params.client_max_window_bits = this._options.clientMaxWindowBits; } } else if ( this._options.clientMaxWindowBits === false || (typeof this._options.clientMaxWindowBits === 'number' && params.client_max_window_bits > this._options.clientMaxWindowBits) ) { throw new Error( 'Unexpected or invalid parameter "client_max_window_bits"' ); } return params; } /** * Normalize parameters. * * @param {Array} configurations The extension negotiation offers/reponse * @return {Array} The offers/response with normalized parameters * @private */ normalizeParams(configurations) { configurations.forEach((params) => { Object.keys(params).forEach((key) => { let value = params[key]; if (value.length > 1) { throw new Error(`Parameter "${key}" must have only a single value`); } value = value[0]; if (key === 'client_max_window_bits') { if (value !== true) { const num = +value; if (!Number.isInteger(num) || num < 8 || num > 15) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } value = num; } else if (!this._isServer) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } } else if (key === 'server_max_window_bits') { const num = +value; if (!Number.isInteger(num) || num < 8 || num > 15) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } value = num; } else if ( key === 'client_no_context_takeover' || key === 'server_no_context_takeover' ) { if (value !== true) { throw new TypeError( `Invalid value for parameter "${key}": ${value}` ); } } else { throw new Error(`Unknown parameter "${key}"`); } params[key] = value; }); }); return configurations; } /** * Decompress data. Concurrency limited. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @public */ decompress(data, fin, callback) { zlibLimiter.add((done) => { this._decompress(data, fin, (err, result) => { done(); callback(err, result); }); }); } /** * Compress data. Concurrency limited. * * @param {(Buffer|String)} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @public */ compress(data, fin, callback) { zlibLimiter.add((done) => { this._compress(data, fin, (err, result) => { done(); callback(err, result); }); }); } /** * Decompress data. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @private */ _decompress(data, fin, callback) { const endpoint = this._isServer ? 'client' : 'server'; if (!this._inflate) { const key = `${endpoint}_max_window_bits`; const windowBits = typeof this.params[key] !== 'number' ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; this._inflate = zlib.createInflateRaw({ ...this._options.zlibInflateOptions, windowBits }); this._inflate[kPerMessageDeflate] = this; this._inflate[kTotalLength] = 0; this._inflate[kBuffers] = []; this._inflate.on('error', inflateOnError); this._inflate.on('data', inflateOnData); } this._inflate[kCallback] = callback; this._inflate.write(data); if (fin) this._inflate.write(TRAILER); this._inflate.flush(() => { const err = this._inflate[kError]; if (err) { this._inflate.close(); this._inflate = null; callback(err); return; } const data = bufferUtil.concat( this._inflate[kBuffers], this._inflate[kTotalLength] ); if (this._inflate._readableState.endEmitted) { this._inflate.close(); this._inflate = null; } else { this._inflate[kTotalLength] = 0; this._inflate[kBuffers] = []; if (fin && this.params[`${endpoint}_no_context_takeover`]) { this._inflate.reset(); } } callback(null, data); }); } /** * Compress data. * * @param {(Buffer|String)} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @private */ _compress(data, fin, callback) { const endpoint = this._isServer ? 'server' : 'client'; if (!this._deflate) { const key = `${endpoint}_max_window_bits`; const windowBits = typeof this.params[key] !== 'number' ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; this._deflate = zlib.createDeflateRaw({ ...this._options.zlibDeflateOptions, windowBits }); this._deflate[kTotalLength] = 0; this._deflate[kBuffers] = []; this._deflate.on('data', deflateOnData); } this._deflate[kCallback] = callback; this._deflate.write(data); this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { if (!this._deflate) { // // The deflate stream was closed while data was being processed. // return; } let data = bufferUtil.concat( this._deflate[kBuffers], this._deflate[kTotalLength] ); if (fin) { data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4); } // // Ensure that the callback will not be called again in // `PerMessageDeflate#cleanup()`. // this._deflate[kCallback] = null; this._deflate[kTotalLength] = 0; this._deflate[kBuffers] = []; if (fin && this.params[`${endpoint}_no_context_takeover`]) { this._deflate.reset(); } callback(null, data); }); } } permessageDeflate = PerMessageDeflate; /** * The listener of the `zlib.DeflateRaw` stream `'data'` event. * * @param {Buffer} chunk A chunk of data * @private */ function deflateOnData(chunk) { this[kBuffers].push(chunk); this[kTotalLength] += chunk.length; } /** * The listener of the `zlib.InflateRaw` stream `'data'` event. * * @param {Buffer} chunk A chunk of data * @private */ function inflateOnData(chunk) { this[kTotalLength] += chunk.length; if ( this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload ) { this[kBuffers].push(chunk); return; } this[kError] = new RangeError('Max payload size exceeded'); this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; this[kError][kStatusCode] = 1009; this.removeListener('data', inflateOnData); this.reset(); } /** * The listener of the `zlib.InflateRaw` stream `'error'` event. * * @param {Error} err The emitted error * @private */ function inflateOnError(err) { // // There is no need to call `Zlib#close()` as the handle is automatically // closed when an error is emitted. // this[kPerMessageDeflate]._inflate = null; err[kStatusCode] = 1007; this[kCallback](err); } return permessageDeflate; } var validation = {exports: {}}; var hasRequiredValidation; function requireValidation () { if (hasRequiredValidation) return validation.exports; hasRequiredValidation = 1; const { isUtf8 } = require$$0$1; const { hasBlob } = requireConstants$1(); // // Allowed token characters: // // '!', '#', '$', '%', '&', ''', '*', '+', '-', // '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' // // tokenChars[32] === 0 // ' ' // tokenChars[33] === 1 // '!' // tokenChars[34] === 0 // '"' // ... // // prettier-ignore const tokenChars = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 ]; /** * Checks if a status code is allowed in a close frame. * * @param {Number} code The status code * @return {Boolean} `true` if the status code is valid, else `false` * @public */ function isValidStatusCode(code) { return ( (code >= 1000 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006) || (code >= 3000 && code <= 4999) ); } /** * Checks if a given buffer contains only correct UTF-8. * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by * Markus Kuhn. * * @param {Buffer} buf The buffer to check * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false` * @public */ function _isValidUTF8(buf) { const len = buf.length; let i = 0; while (i < len) { if ((buf[i] & 0x80) === 0) { // 0xxxxxxx i++; } else if ((buf[i] & 0xe0) === 0xc0) { // 110xxxxx 10xxxxxx if ( i + 1 === len || (buf[i + 1] & 0xc0) !== 0x80 || (buf[i] & 0xfe) === 0xc0 // Overlong ) { return false; } i += 2; } else if ((buf[i] & 0xf0) === 0xe0) { // 1110xxxx 10xxxxxx 10xxxxxx if ( i + 2 >= len || (buf[i + 1] & 0xc0) !== 0x80 || (buf[i + 2] & 0xc0) !== 0x80 || (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF) ) { return false; } i += 3; } else if ((buf[i] & 0xf8) === 0xf0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx if ( i + 3 >= len || (buf[i + 1] & 0xc0) !== 0x80 || (buf[i + 2] & 0xc0) !== 0x80 || (buf[i + 3] & 0xc0) !== 0x80 || (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong (buf[i] === 0xf4 && buf[i + 1] > 0x8f) || buf[i] > 0xf4 // > U+10FFFF ) { return false; } i += 4; } else { return false; } } return true; } /** * Determines whether a value is a `Blob`. * * @param {*} value The value to be tested * @return {Boolean} `true` if `value` is a `Blob`, else `false` * @private */ function isBlob(value) { return ( hasBlob && typeof value === 'object' && typeof value.arrayBuffer === 'function' && typeof value.type === 'string' && typeof value.stream === 'function' && (value[Symbol.toStringTag] === 'Blob' || value[Symbol.toStringTag] === 'File') ); } validation.exports = { isBlob, isValidStatusCode, isValidUTF8: _isValidUTF8, tokenChars }; if (isUtf8) { validation.exports.isValidUTF8 = function (buf) { return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf); }; } /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) { try { const isValidUTF8 = require('utf-8-validate'); validation.exports.isValidUTF8 = function (buf) { return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf); }; } catch (e) { // Continue regardless of the error. } } return validation.exports; } var receiver; var hasRequiredReceiver; function requireReceiver () { if (hasRequiredReceiver) return receiver; hasRequiredReceiver = 1; const { Writable } = require$$0$2; const PerMessageDeflate = requirePermessageDeflate(); const { BINARY_TYPES, EMPTY_BUFFER, kStatusCode, kWebSocket } = requireConstants$1(); const { concat, toArrayBuffer, unmask } = requireBufferUtil(); const { isValidStatusCode, isValidUTF8 } = requireValidation(); const FastBuffer = Buffer[Symbol.species]; const GET_INFO = 0; const GET_PAYLOAD_LENGTH_16 = 1; const GET_PAYLOAD_LENGTH_64 = 2; const GET_MASK = 3; const GET_DATA = 4; const INFLATING = 5; const DEFER_EVENT = 6; /** * HyBi Receiver implementation. * * @extends Writable */ class Receiver extends Writable { /** * Creates a Receiver instance. * * @param {Object} [options] Options object * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted * multiple times in the same tick * @param {String} [options.binaryType=nodebuffer] The type for binary data * @param {Object} [options.extensions] An object containing the negotiated * extensions * @param {Boolean} [options.isServer=false] Specifies whether to operate in * client or server mode * @param {Number} [options.maxPayload=0] The maximum allowed message length * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or * not to skip UTF-8 validation for text and close messages */ constructor(options = {}) { super(); this._allowSynchronousEvents = options.allowSynchronousEvents !== undefined ? options.allowSynchronousEvents : true; this._binaryType = options.binaryType || BINARY_TYPES[0]; this._extensions = options.extensions || {}; this._isServer = !!options.isServer; this._maxPayload = options.maxPayload | 0; this._skipUTF8Validation = !!options.skipUTF8Validation; this[kWebSocket] = undefined; this._bufferedBytes = 0; this._buffers = []; this._compressed = false; this._payloadLength = 0; this._mask = undefined; this._fragmented = 0; this._masked = false; this._fin = false; this._opcode = 0; this._totalPayloadLength = 0; this._messageLength = 0; this._fragments = []; this._errored = false; this._loop = false; this._state = GET_INFO; } /** * Implements `Writable.prototype._write()`. * * @param {Buffer} chunk The chunk of data to write * @param {String} encoding The character encoding of `chunk` * @param {Function} cb Callback * @private */ _write(chunk, encoding, cb) { if (this._opcode === 0x08 && this._state == GET_INFO) return cb(); this._bufferedBytes += chunk.length; this._buffers.push(chunk); this.startLoop(cb); } /** * Consumes `n` bytes from the buffered data. * * @param {Number} n The number of bytes to consume * @return {Buffer} The consumed bytes * @private */ consume(n) { this._bufferedBytes -= n; if (n === this._buffers[0].length) return this._buffers.shift(); if (n < this._buffers[0].length) { const buf = this._buffers[0]; this._buffers[0] = new FastBuffer( buf.buffer, buf.byteOffset + n, buf.length - n ); return new FastBuffer(buf.buffer, buf.byteOffset, n); } const dst = Buffer.allocUnsafe(n); do { const buf = this._buffers[0]; const offset = dst.length - n; if (n >= buf.length) { dst.set(this._buffers.shift(), offset); } else { dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); this._buffers[0] = new FastBuffer( buf.buffer, buf.byteOffset + n, buf.length - n ); } n -= buf.length; } while (n > 0); return dst; } /** * Starts the parsing loop. * * @param {Function} cb Callback * @private */ startLoop(cb) { this._loop = true; do { switch (this._state) { case GET_INFO: this.getInfo(cb); break; case GET_PAYLOAD_LENGTH_16: this.getPayloadLength16(cb); break; case GET_PAYLOAD_LENGTH_64: this.getPayloadLength64(cb); break; case GET_MASK: this.getMask(); break; case GET_DATA: this.getData(cb); break; case INFLATING: case DEFER_EVENT: this._loop = false; return; } } while (this._loop); if (!this._errored) cb(); } /** * Reads the first two bytes of a frame. * * @param {Function} cb Callback * @private */ getInfo(cb) { if (this._bufferedBytes < 2) { this._loop = false; return; } const buf = this.consume(2); if ((buf[0] & 0x30) !== 0x00) { const error = this.createError( RangeError, 'RSV2 and RSV3 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_2_3' ); cb(error); return; } const compressed = (buf[0] & 0x40) === 0x40; if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { const error = this.createError( RangeError, 'RSV1 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_1' ); cb(error); return; } this._fin = (buf[0] & 0x80) === 0x80; this._opcode = buf[0] & 0x0f; this._payloadLength = buf[1] & 0x7f; if (this._opcode === 0x00) { if (compressed) { const error = this.createError( RangeError, 'RSV1 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_1' ); cb(error); return; } if (!this._fragmented) { const error = this.createError( RangeError, 'invalid opcode 0', true, 1002, 'WS_ERR_INVALID_OPCODE' ); cb(error); return; } this._opcode = this._fragmented; } else if (this._opcode === 0x01 || this._opcode === 0x02) { if (this._fragmented) { const error = this.createError( RangeError, `invalid opcode ${this._opcode}`, true, 1002, 'WS_ERR_INVALID_OPCODE' ); cb(error); return; } this._compressed = compressed; } else if (this._opcode > 0x07 && this._opcode < 0x0b) { if (!this._fin) { const error = this.createError( RangeError, 'FIN must be set', true, 1002, 'WS_ERR_EXPECTED_FIN' ); cb(error); return; } if (compressed) { const error = this.createError( RangeError, 'RSV1 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_1' ); cb(error); return; } if ( this._payloadLength > 0x7d || (this._opcode === 0x08 && this._payloadLength === 1) ) { const error = this.createError( RangeError, `invalid payload length ${this._payloadLength}`, true, 1002, 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH' ); cb(error); return; } } else { const error = this.createError( RangeError, `invalid opcode ${this._opcode}`, true, 1002, 'WS_ERR_INVALID_OPCODE' ); cb(error); return; } if (!this._fin && !this._fragmented) this._fragmented = this._opcode; this._masked = (buf[1] & 0x80) === 0x80; if (this._isServer) { if (!this._masked) { const error = this.createError( RangeError, 'MASK must be set', true, 1002, 'WS_ERR_EXPECTED_MASK' ); cb(error); return; } } else if (this._masked) { const error = this.createError( RangeError, 'MASK must be clear', true, 1002, 'WS_ERR_UNEXPECTED_MASK' ); cb(error); return; } if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; else this.haveLength(cb); } /** * Gets extended payload length (7+16). * * @param {Function} cb Callback * @private */ getPayloadLength16(cb) { if (this._bufferedBytes < 2) { this._loop = false; return; } this._payloadLength = this.consume(2).readUInt16BE(0); this.haveLength(cb); } /** * Gets extended payload length (7+64). * * @param {Function} cb Callback * @private */ getPayloadLength64(cb) { if (this._bufferedBytes < 8) { this._loop = false; return; } const buf = this.consume(8); const num = buf.readUInt32BE(0); // // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned // if payload length is greater than this number. // if (num > Math.pow(2, 53 - 32) - 1) { const error = this.createError( RangeError, 'Unsupported WebSocket frame: payload length > 2^53 - 1', false, 1009, 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH' ); cb(error); return; } this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); this.haveLength(cb); } /** * Payload length has been read. * * @param {Function} cb Callback * @private */ haveLength(cb) { if (this._payloadLength && this._opcode < 0x08) { this._totalPayloadLength += this._payloadLength; if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { const error = this.createError( RangeError, 'Max payload size exceeded', false, 1009, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' ); cb(error); return; } } if (this._masked) this._state = GET_MASK; else this._state = GET_DATA; } /** * Reads mask bytes. * * @private */ getMask() { if (this._bufferedBytes < 4) { this._loop = false; return; } this._mask = this.consume(4); this._state = GET_DATA; } /** * Reads data bytes. * * @param {Function} cb Callback * @private */ getData(cb) { let data = EMPTY_BUFFER; if (this._payloadLength) { if (this._bufferedBytes < this._payloadLength) { this._loop = false; return; } data = this.consume(this._payloadLength); if ( this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0 ) { unmask(data, this._mask); } } if (this._opcode > 0x07) { this.controlMessage(data, cb); return; } if (this._compressed) { this._state = INFLATING; this.decompress(data, cb); return; } if (data.length) { // // This message is not compressed so its length is the sum of the payload // length of all fragments. // this._messageLength = this._totalPayloadLength; this._fragments.push(data); } this.dataMessage(cb); } /** * Decompresses data. * * @param {Buffer} data Compressed data * @param {Function} cb Callback * @private */ decompress(data, cb) { const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; perMessageDeflate.decompress(data, this._fin, (err, buf) => { if (err) return cb(err); if (buf.length) { this._messageLength += buf.length; if (this._messageLength > this._maxPayload && this._maxPayload > 0) { const error = this.createError( RangeError, 'Max payload size exceeded', false, 1009, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' ); cb(error); return; } this._fragments.push(buf); } this.dataMessage(cb); if (this._state === GET_INFO) this.startLoop(cb); }); } /** * Handles a data message. * * @param {Function} cb Callback * @private */ dataMessage(cb) { if (!this._fin) { this._state = GET_INFO; return; } const messageLength = this._messageLength; const fragments = this._fragments; this._totalPayloadLength = 0; this._messageLength = 0; this._fragmented = 0; this._fragments = []; if (this._opcode === 2) { let data; if (this._binaryType === 'nodebuffer') { data = concat(fragments, messageLength); } else if (this._binaryType === 'arraybuffer') { data = toArrayBuffer(concat(fragments, messageLength)); } else if (this._binaryType === 'blob') { data = new Blob(fragments); } else { data = fragments; } if (this._allowSynchronousEvents) { this.emit('message', data, true); this._state = GET_INFO; } else { this._state = DEFER_EVENT; setImmediate(() => { this.emit('message', data, true); this._state = GET_INFO; this.startLoop(cb); }); } } else { const buf = concat(fragments, messageLength); if (!this._skipUTF8Validation && !isValidUTF8(buf)) { const error = this.createError( Error, 'invalid UTF-8 sequence', true, 1007, 'WS_ERR_INVALID_UTF8' ); cb(error); return; } if (this._state === INFLATING || this._allowSynchronousEvents) { this.emit('message', buf, false); this._state = GET_INFO; } else { this._state = DEFER_EVENT; setImmediate(() => { this.emit('message', buf, false); this._state = GET_INFO; this.startLoop(cb); }); } } } /** * Handles a control message. * * @param {Buffer} data Data to handle * @return {(Error|RangeError|undefined)} A possible error * @private */ controlMessage(data, cb) { if (this._opcode === 0x08) { if (data.length === 0) { this._loop = false; this.emit('conclude', 1005, EMPTY_BUFFER); this.end(); } else { const code = data.readUInt16BE(0); if (!isValidStatusCode(code)) { const error = this.createError( RangeError, `invalid status code ${code}`, true, 1002, 'WS_ERR_INVALID_CLOSE_CODE' ); cb(error); return; } const buf = new FastBuffer( data.buffer, data.byteOffset + 2, data.length - 2 ); if (!this._skipUTF8Validation && !isValidUTF8(buf)) { const error = this.createError( Error, 'invalid UTF-8 sequence', true, 1007, 'WS_ERR_INVALID_UTF8' ); cb(error); return; } this._loop = false; this.emit('conclude', code, buf); this.end(); } this._state = GET_INFO; return; } if (this._allowSynchronousEvents) { this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data); this._state = GET_INFO; } else { this._state = DEFER_EVENT; setImmediate(() => { this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data); this._state = GET_INFO; this.startLoop(cb); }); } } /** * Builds an error object. * * @param {function(new:Error|RangeError)} ErrorCtor The error constructor * @param {String} message The error message * @param {Boolean} prefix Specifies whether or not to add a default prefix to * `message` * @param {Number} statusCode The status code * @param {String} errorCode The exposed error code * @return {(Error|RangeError)} The error * @private */ createError(ErrorCtor, message, prefix, statusCode, errorCode) { this._loop = false; this._errored = true; const err = new ErrorCtor( prefix ? `Invalid WebSocket frame: ${message}` : message ); Error.captureStackTrace(err, this.createError); err.code = errorCode; err[kStatusCode] = statusCode; return err; } } receiver = Receiver; return receiver; } requireReceiver(); /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */ var sender; var hasRequiredSender; function requireSender () { if (hasRequiredSender) return sender; hasRequiredSender = 1; const { randomFillSync } = require$$1; const PerMessageDeflate = requirePermessageDeflate(); const { EMPTY_BUFFER, kWebSocket, NOOP } = requireConstants$1(); const { isBlob, isValidStatusCode } = requireValidation(); const { mask: applyMask, toBuffer } = requireBufferUtil(); const kByteLength = Symbol('kByteLength'); const maskBuffer = Buffer.alloc(4); const RANDOM_POOL_SIZE = 8 * 1024; let randomPool; let randomPoolPointer = RANDOM_POOL_SIZE; const DEFAULT = 0; const DEFLATING = 1; const GET_BLOB_DATA = 2; /** * HyBi Sender implementation. */ class Sender { /** * Creates a Sender instance. * * @param {Duplex} socket The connection socket * @param {Object} [extensions] An object containing the negotiated extensions * @param {Function} [generateMask] The function used to generate the masking * key */ constructor(socket, extensions, generateMask) { this._extensions = extensions || {}; if (generateMask) { this._generateMask = generateMask; this._maskBuffer = Buffer.alloc(4); } this._socket = socket; this._firstFragment = true; this._compress = false; this._bufferedBytes = 0; this._queue = []; this._state = DEFAULT; this.onerror = NOOP; this[kWebSocket] = undefined; } /** * Frames a piece of data according to the HyBi WebSocket protocol. * * @param {(Buffer|String)} data The data to frame * @param {Object} options Options object * @param {Boolean} [options.fin=false] Specifies whether or not to set the * FIN bit * @param {Function} [options.generateMask] The function used to generate the * masking key * @param {Boolean} [options.mask=false] Specifies whether or not to mask * `data` * @param {Buffer} [options.maskBuffer] The buffer used to store the masking * key * @param {Number} options.opcode The opcode * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be * modified * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the * RSV1 bit * @return {(Buffer|String)[]} The framed data * @public */ static frame(data, options) { let mask; let merge = false; let offset = 2; let skipMasking = false; if (options.mask) { mask = options.maskBuffer || maskBuffer; if (options.generateMask) { options.generateMask(mask); } else { if (randomPoolPointer === RANDOM_POOL_SIZE) { /* istanbul ignore else */ if (randomPool === undefined) { // // This is lazily initialized because server-sent frames must not // be masked so it may never be used. // randomPool = Buffer.alloc(RANDOM_POOL_SIZE); } randomFillSync(randomPool, 0, RANDOM_POOL_SIZE); randomPoolPointer = 0; } mask[0] = randomPool[randomPoolPointer++]; mask[1] = randomPool[randomPoolPointer++]; mask[2] = randomPool[randomPoolPointer++]; mask[3] = randomPool[randomPoolPointer++]; } skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; offset = 6; } let dataLength; if (typeof data === 'string') { if ( (!options.mask || skipMasking) && options[kByteLength] !== undefined ) { dataLength = options[kByteLength]; } else { data = Buffer.from(data); dataLength = data.length; } } else { dataLength = data.length; merge = options.mask && options.readOnly && !skipMasking; } let payloadLength = dataLength; if (dataLength >= 65536) { offset += 8; payloadLength = 127; } else if (dataLength > 125) { offset += 2; payloadLength = 126; } const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset); target[0] = options.fin ? options.opcode | 0x80 : options.opcode; if (options.rsv1) target[0] |= 0x40; target[1] = payloadLength; if (payloadLength === 126) { target.writeUInt16BE(dataLength, 2); } else if (payloadLength === 127) { target[2] = target[3] = 0; target.writeUIntBE(dataLength, 4, 6); } if (!options.mask) return [target, data]; target[1] |= 0x80; target[offset - 4] = mask[0]; target[offset - 3] = mask[1]; target[offset - 2] = mask[2]; target[offset - 1] = mask[3]; if (skipMasking) return [target, data]; if (merge) { applyMask(data, mask, target, offset, dataLength); return [target]; } applyMask(data, mask, data, 0, dataLength); return [target, data]; } /** * Sends a close message to the other peer. * * @param {Number} [code] The status code component of the body * @param {(String|Buffer)} [data] The message component of the body * @param {Boolean} [mask=false] Specifies whether or not to mask the message * @param {Function} [cb] Callback * @public */ close(code, data, mask, cb) { let buf; if (code === undefined) { buf = EMPTY_BUFFER; } else if (typeof code !== 'number' || !isValidStatusCode(code)) { throw new TypeError('First argument must be a valid error code number'); } else if (data === undefined || !data.length) { buf = Buffer.allocUnsafe(2); buf.writeUInt16BE(code, 0); } else { const length = Buffer.byteLength(data); if (length > 123) { throw new RangeError('The message must not be greater than 123 bytes'); } buf = Buffer.allocUnsafe(2 + length); buf.writeUInt16BE(code, 0); if (typeof data === 'string') { buf.write(data, 2); } else { buf.set(data, 2); } } const options = { [kByteLength]: buf.length, fin: true, generateMask: this._generateMask, mask, maskBuffer: this._maskBuffer, opcode: 0x08, readOnly: false, rsv1: false }; if (this._state !== DEFAULT) { this.enqueue([this.dispatch, buf, false, options, cb]); } else { this.sendFrame(Sender.frame(buf, options), cb); } } /** * Sends a ping message to the other peer. * * @param {*} data The message to send * @param {Boolean} [mask=false] Specifies whether or not to mask `data` * @param {Function} [cb] Callback * @public */ ping(data, mask, cb) { let byteLength; let readOnly; if (typeof data === 'string') { byteLength = Buffer.byteLength(data); readOnly = false; } else if (isBlob(data)) { byteLength = data.size; readOnly = false; } else { data = toBuffer(data); byteLength = data.length; readOnly = toBuffer.readOnly; } if (byteLength > 125) { throw new RangeError('The data size must not be greater than 125 bytes'); } const options = { [kByteLength]: byteLength, fin: true, generateMask: this._generateMask, mask, maskBuffer: this._maskBuffer, opcode: 0x09, readOnly, rsv1: false }; if (isBlob(data)) { if (this._state !== DEFAULT) { this.enqueue([this.getBlobData, data, false, options, cb]); } else { this.getBlobData(data, false, options, cb); } } else if (this._state !== DEFAULT) { this.enqueue([this.dispatch, data, false, options, cb]); } else { this.sendFrame(Sender.frame(data, options), cb); } } /** * Sends a pong message to the other peer. * * @param {*} data The message to send * @param {Boolean} [mask=false] Specifies whether or not to mask `data` * @param {Function} [cb] Callback * @public */ pong(data, mask, cb) { let byteLength; let readOnly; if (typeof data === 'string') { byteLength = Buffer.byteLength(data); readOnly = false; } else if (isBlob(data)) { byteLength = data.size; readOnly = false; } else { data = toBuffer(data); byteLength = data.length; readOnly = toBuffer.readOnly; } if (byteLength > 125) { throw new RangeError('The data size must not be greater than 125 bytes'); } const options = { [kByteLength]: byteLength, fin: true, generateMask: this._generateMask, mask, maskBuffer: this._maskBuffer, opcode: 0x0a, readOnly, rsv1: false }; if (isBlob(data)) { if (this._state !== DEFAULT) { this.enqueue([this.getBlobData, data, false, options, cb]); } else { this.getBlobData(data, false, options, cb); } } else if (this._state !== DEFAULT) { this.enqueue([this.dispatch, data, false, options, cb]); } else { this.sendFrame(Sender.frame(data, options), cb); } } /** * Sends a data message to the other peer. * * @param {*} data The message to send * @param {Object} options Options object * @param {Boolean} [options.binary=false] Specifies whether `data` is binary * or text * @param {Boolean} [options.compress=false] Specifies whether or not to * compress `data` * @param {Boolean} [options.fin=false] Specifies whether the fragment is the * last one * @param {Boolean} [options.mask=false] Specifies whether or not to mask * `data` * @param {Function} [cb] Callback * @public */ send(data, options, cb) { const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; let opcode = options.binary ? 2 : 1; let rsv1 = options.compress; let byteLength; let readOnly; if (typeof data === 'string') { byteLength = Buffer.byteLength(data); readOnly = false; } else if (isBlob(data)) { byteLength = data.size; readOnly = false; } else { data = toBuffer(data); byteLength = data.length; readOnly = toBuffer.readOnly; } if (this._firstFragment) { this._firstFragment = false; if ( rsv1 && perMessageDeflate && perMessageDeflate.params[ perMessageDeflate._isServer ? 'server_no_context_takeover' : 'client_no_context_takeover' ] ) { rsv1 = byteLength >= perMessageDeflate._threshold; } this._compress = rsv1; } else { rsv1 = false; opcode = 0; } if (options.fin) this._firstFragment = true; const opts = { [kByteLength]: byteLength, fin: options.fin, generateMask: this._generateMask, mask: options.mask, maskBuffer: this._maskBuffer, opcode, readOnly, rsv1 }; if (isBlob(data)) { if (this._state !== DEFAULT) { this.enqueue([this.getBlobData, data, this._compress, opts, cb]); } else { this.getBlobData(data, this._compress, opts, cb); } } else if (this._state !== DEFAULT) { this.enqueue([this.dispatch, data, this._compress, opts, cb]); } else { this.dispatch(data, this._compress, opts, cb); } } /** * Gets the contents of a blob as binary data. * * @param {Blob} blob The blob * @param {Boolean} [compress=false] Specifies whether or not to compress * the data * @param {Object} options Options object * @param {Boolean} [options.fin=false] Specifies whether or not to set the * FIN bit * @param {Function} [options.generateMask] The function used to generate the * masking key * @param {Boolean} [options.mask=false] Specifies whether or not to mask * `data` * @param {Buffer} [options.maskBuffer] The buffer used to store the masking * key * @param {Number} options.opcode The opcode * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be * modified * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the * RSV1 bit * @param {Function} [cb] Callback * @private */ getBlobData(blob, compress, options, cb) { this._bufferedBytes += options[kByteLength]; this._state = GET_BLOB_DATA; blob .arrayBuffer() .then((arrayBuffer) => { if (this._socket.destroyed) { const err = new Error( 'The socket was closed while the blob was being read' ); // // `callCallbacks` is called in the next tick to ensure that errors // that might be thrown in the callbacks behave like errors thrown // outside the promise chain. // process.nextTick(callCallbacks, this, err, cb); return; } this._bufferedBytes -= options[kByteLength]; const data = toBuffer(arrayBuffer); if (!compress) { this._state = DEFAULT; this.sendFrame(Sender.frame(data, options), cb); this.dequeue(); } else { this.dispatch(data, compress, options, cb); } }) .catch((err) => { // // `onError` is called in the next tick for the same reason that // `callCallbacks` above is. // process.nextTick(onError, this, err, cb); }); } /** * Dispatches a message. * * @param {(Buffer|String)} data The message to send * @param {Boolean} [compress=false] Specifies whether or not to compress * `data` * @param {Object} options Options object * @param {Boolean} [options.fin=false] Specifies whether or not to set the * FIN bit * @param {Function} [options.generateMask] The function used to generate the * masking key * @param {Boolean} [options.mask=false] Specifies whether or not to mask * `data` * @param {Buffer} [options.maskBuffer] The buffer used to store the masking * key * @param {Number} options.opcode The opcode * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be * modified * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the * RSV1 bit * @param {Function} [cb] Callback * @private */ dispatch(data, compress, options, cb) { if (!compress) { this.sendFrame(Sender.frame(data, options), cb); return; } const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; this._bufferedBytes += options[kByteLength]; this._state = DEFLATING; perMessageDeflate.compress(data, options.fin, (_, buf) => { if (this._socket.destroyed) { const err = new Error( 'The socket was closed while data was being compressed' ); callCallbacks(this, err, cb); return; } this._bufferedBytes -= options[kByteLength]; this._state = DEFAULT; options.readOnly = false; this.sendFrame(Sender.frame(buf, options), cb); this.dequeue(); }); } /** * Executes queued send operations. * * @private */ dequeue() { while (this._state === DEFAULT && this._queue.length) { const params = this._queue.shift(); this._bufferedBytes -= params[3][kByteLength]; Reflect.apply(params[0], this, params.slice(1)); } } /** * Enqueues a send operation. * * @param {Array} params Send operation parameters. * @private */ enqueue(params) { this._bufferedBytes += params[3][kByteLength]; this._queue.push(params); } /** * Sends a frame. * * @param {Buffer[]} list The frame to send * @param {Function} [cb] Callback * @private */ sendFrame(list, cb) { if (list.length === 2) { this._socket.cork(); this._socket.write(list[0]); this._socket.write(list[1], cb); this._socket.uncork(); } else { this._socket.write(list[0], cb); } } } sender = Sender; /** * Calls queued callbacks with an error. * * @param {Sender} sender The `Sender` instance * @param {Error} err The error to call the callbacks with * @param {Function} [cb] The first callback * @private */ function callCallbacks(sender, err, cb) { if (typeof cb === 'function') cb(err); for (let i = 0; i < sender._queue.length; i++) { const params = sender._queue[i]; const callback = params[params.length - 1]; if (typeof callback === 'function') callback(err); } } /** * Handles a `Sender` error. * * @param {Sender} sender The `Sender` instance * @param {Error} err The error * @param {Function} [cb] The first pending callback * @private */ function onError(sender, err, cb) { callCallbacks(sender, err, cb); sender.onerror(err); } return sender; } requireSender(); var eventTarget; var hasRequiredEventTarget; function requireEventTarget () { if (hasRequiredEventTarget) return eventTarget; hasRequiredEventTarget = 1; const { kForOnEventAttribute, kListener } = requireConstants$1(); const kCode = Symbol('kCode'); const kData = Symbol('kData'); const kError = Symbol('kError'); const kMessage = Symbol('kMessage'); const kReason = Symbol('kReason'); const kTarget = Symbol('kTarget'); const kType = Symbol('kType'); const kWasClean = Symbol('kWasClean'); /** * Class representing an event. */ class Event { /** * Create a new `Event`. * * @param {String} type The name of the event * @throws {TypeError} If the `type` argument is not specified */ constructor(type) { this[kTarget] = null; this[kType] = type; } /** * @type {*} */ get target() { return this[kTarget]; } /** * @type {String} */ get type() { return this[kType]; } } Object.defineProperty(Event.prototype, 'target', { enumerable: true }); Object.defineProperty(Event.prototype, 'type', { enumerable: true }); /** * Class representing a close event. * * @extends Event */ class CloseEvent extends Event { /** * Create a new `CloseEvent`. * * @param {String} type The name of the event * @param {Object} [options] A dictionary object that allows for setting * attributes via object members of the same name * @param {Number} [options.code=0] The status code explaining why the * connection was closed * @param {String} [options.reason=''] A human-readable string explaining why * the connection was closed * @param {Boolean} [options.wasClean=false] Indicates whether or not the * connection was cleanly closed */ constructor(type, options = {}) { super(type); this[kCode] = options.code === undefined ? 0 : options.code; this[kReason] = options.reason === undefined ? '' : options.reason; this[kWasClean] = options.wasClean === undefined ? false : options.wasClean; } /** * @type {Number} */ get code() { return this[kCode]; } /** * @type {String} */ get reason() { return this[kReason]; } /** * @type {Boolean} */ get wasClean() { return this[kWasClean]; } } Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true }); Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true }); Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true }); /** * Class representing an error event. * * @extends Event */ class ErrorEvent extends Event { /** * Create a new `ErrorEvent`. * * @param {String} type The name of the event * @param {Object} [options] A dictionary object that allows for setting * attributes via object members of the same name * @param {*} [options.error=null] The error that generated this event * @param {String} [options.message=''] The error message */ constructor(type, options = {}) { super(type); this[kError] = options.error === undefined ? null : options.error; this[kMessage] = options.message === undefined ? '' : options.message; } /** * @type {*} */ get error() { return this[kError]; } /** * @type {String} */ get message() { return this[kMessage]; } } Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true }); Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true }); /** * Class representing a message event. * * @extends Event */ class MessageEvent extends Event { /** * Create a new `MessageEvent`. * * @param {String} type The name of the event * @param {Object} [options] A dictionary object that allows for setting * attributes via object members of the same name * @param {*} [options.data=null] The message content */ constructor(type, options = {}) { super(type); this[kData] = options.data === undefined ? null : options.data; } /** * @type {*} */ get data() { return this[kData]; } } Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true }); /** * This provides methods for emulating the `EventTarget` interface. It's not * meant to be used directly. * * @mixin */ const EventTarget = { /** * Register an event listener. * * @param {String} type A string representing the event type to listen for * @param {(Function|Object)} handler The listener to add * @param {Object} [options] An options object specifies characteristics about * the event listener * @param {Boolean} [options.once=false] A `Boolean` indicating that the * listener should be invoked at most once after being added. If `true`, * the listener would be automatically removed when invoked. * @public */ addEventListener(type, handler, options = {}) { for (const listener of this.listeners(type)) { if ( !options[kForOnEventAttribute] && listener[kListener] === handler && !listener[kForOnEventAttribute] ) { return; } } let wrapper; if (type === 'message') { wrapper = function onMessage(data, isBinary) { const event = new MessageEvent('message', { data: isBinary ? data : data.toString() }); event[kTarget] = this; callListener(handler, this, event); }; } else if (type === 'close') { wrapper = function onClose(code, message) { const event = new CloseEvent('close', { code, reason: message.toString(), wasClean: this._closeFrameReceived && this._closeFrameSent }); event[kTarget] = this; callListener(handler, this, event); }; } else if (type === 'error') { wrapper = function onError(error) { const event = new ErrorEvent('error', { error, message: error.message }); event[kTarget] = this; callListener(handler, this, event); }; } else if (type === 'open') { wrapper = function onOpen() { const event = new Event('open'); event[kTarget] = this; callListener(handler, this, event); }; } else { return; } wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute]; wrapper[kListener] = handler; if (options.once) { this.once(type, wrapper); } else { this.on(type, wrapper); } }, /** * Remove an event listener. * * @param {String} type A string representing the event type to remove * @param {(Function|Object)} handler The listener to remove * @public */ removeEventListener(type, handler) { for (const listener of this.listeners(type)) { if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { this.removeListener(type, listener); break; } } } }; eventTarget = { CloseEvent, ErrorEvent, Event, EventTarget, MessageEvent }; /** * Call an event listener * * @param {(Function|Object)} listener The listener to call * @param {*} thisArg The value to use as `this`` when calling the listener * @param {Event} event The event to pass to the listener * @private */ function callListener(listener, thisArg, event) { if (typeof listener === 'object' && listener.handleEvent) { listener.handleEvent.call(listener, event); } else { listener.call(thisArg, event); } } return eventTarget; } var extension; var hasRequiredExtension; function requireExtension () { if (hasRequiredExtension) return extension; hasRequiredExtension = 1; const { tokenChars } = requireValidation(); /** * Adds an offer to the map of extension offers or a parameter to the map of * parameters. * * @param {Object} dest The map of extension offers or parameters * @param {String} name The extension or parameter name * @param {(Object|Boolean|String)} elem The extension parameters or the * parameter value * @private */ function push(dest, name, elem) { if (dest[name] === undefined) dest[name] = [elem]; else dest[name].push(elem); } /** * Parses the `Sec-WebSocket-Extensions` header into an object. * * @param {String} header The field value of the header * @return {Object} The parsed object * @public */ function parse(header) { const offers = Object.create(null); let params = Object.create(null); let mustUnescape = false; let isEscaping = false; let inQuotes = false; let extensionName; let paramName; let start = -1; let code = -1; let end = -1; let i = 0; for (; i < header.length; i++) { code = header.charCodeAt(i); if (extensionName === undefined) { if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if ( i !== 0 && (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ ) { if (end === -1 && start !== -1) end = i; } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; const name = header.slice(start, end); if (code === 0x2c) { push(offers, name, params); params = Object.create(null); } else { extensionName = name; } start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } else if (paramName === undefined) { if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if (code === 0x20 || code === 0x09) { if (end === -1 && start !== -1) end = i; } else if (code === 0x3b || code === 0x2c) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; push(params, header.slice(start, end), true); if (code === 0x2c) { push(offers, extensionName, params); params = Object.create(null); extensionName = undefined; } start = end = -1; } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) { paramName = header.slice(start, i); start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } else { // // The value of a quoted-string after unescaping must conform to the // token ABNF, so only token characters are valid. // Ref: https://tools.ietf.org/html/rfc6455#section-9.1 // if (isEscaping) { if (tokenChars[code] !== 1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (start === -1) start = i; else if (!mustUnescape) mustUnescape = true; isEscaping = false; } else if (inQuotes) { if (tokenChars[code] === 1) { if (start === -1) start = i; } else if (code === 0x22 /* '"' */ && start !== -1) { inQuotes = false; end = i; } else if (code === 0x5c /* '\' */) { isEscaping = true; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) { inQuotes = true; } else if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if (start !== -1 && (code === 0x20 || code === 0x09)) { if (end === -1) end = i; } else if (code === 0x3b || code === 0x2c) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; let value = header.slice(start, end); if (mustUnescape) { value = value.replace(/\\/g, ''); mustUnescape = false; } push(params, paramName, value); if (code === 0x2c) { push(offers, extensionName, params); params = Object.create(null); extensionName = undefined; } paramName = undefined; start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } } if (start === -1 || inQuotes || code === 0x20 || code === 0x09) { throw new SyntaxError('Unexpected end of input'); } if (end === -1) end = i; const token = header.slice(start, end); if (extensionName === undefined) { push(offers, token, params); } else { if (paramName === undefined) { push(params, token, true); } else if (mustUnescape) { push(params, paramName, token.replace(/\\/g, '')); } else { push(params, paramName, token); } push(offers, extensionName, params); } return offers; } /** * Builds the `Sec-WebSocket-Extensions` header field value. * * @param {Object} extensions The map of extensions and parameters to format * @return {String} A string representing the given object * @public */ function format(extensions) { return Object.keys(extensions) .map((extension) => { let configurations = extensions[extension]; if (!Array.isArray(configurations)) configurations = [configurations]; return configurations .map((params) => { return [extension] .concat( Object.keys(params).map((k) => { let values = params[k]; if (!Array.isArray(values)) values = [values]; return values .map((v) => (v === true ? k : `${k}=${v}`)) .join('; '); }) ) .join('; '); }) .join(', '); }) .join(', '); } extension = { format, parse }; return extension; } /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$", "caughtErrors": "none" }] */ var websocket; var hasRequiredWebsocket; function requireWebsocket () { if (hasRequiredWebsocket) return websocket; hasRequiredWebsocket = 1; const EventEmitter = require$$0$3; const https = require$$1$1; const http = require$$2; const net = require$$3; const tls = require$$4; const { randomBytes, createHash } = require$$1; const { URL } = require$$7; const PerMessageDeflate = requirePermessageDeflate(); const Receiver = requireReceiver(); const Sender = requireSender(); const { isBlob } = requireValidation(); const { BINARY_TYPES, EMPTY_BUFFER, GUID, kForOnEventAttribute, kListener, kStatusCode, kWebSocket, NOOP } = requireConstants$1(); const { EventTarget: { addEventListener, removeEventListener } } = requireEventTarget(); const { format, parse } = requireExtension(); const { toBuffer } = requireBufferUtil(); const closeTimeout = 30 * 1000; const kAborted = Symbol('kAborted'); const protocolVersions = [8, 13]; const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; /** * Class representing a WebSocket. * * @extends EventEmitter */ class WebSocket extends EventEmitter { /** * Create a new `WebSocket`. * * @param {(String|URL)} address The URL to which to connect * @param {(String|String[])} [protocols] The subprotocols * @param {Object} [options] Connection options */ constructor(address, protocols, options) { super(); this._binaryType = BINARY_TYPES[0]; this._closeCode = 1006; this._closeFrameReceived = false; this._closeFrameSent = false; this._closeMessage = EMPTY_BUFFER; this._closeTimer = null; this._errorEmitted = false; this._extensions = {}; this._paused = false; this._protocol = ''; this._readyState = WebSocket.CONNECTING; this._receiver = null; this._sender = null; this._socket = null; if (address !== null) { this._bufferedAmount = 0; this._isServer = false; this._redirects = 0; if (protocols === undefined) { protocols = []; } else if (!Array.isArray(protocols)) { if (typeof protocols === 'object' && protocols !== null) { options = protocols; protocols = []; } else { protocols = [protocols]; } } initAsClient(this, address, protocols, options); } else { this._autoPong = options.autoPong; this._isServer = true; } } /** * For historical reasons, the custom "nodebuffer" type is used by the default * instead of "blob". * * @type {String} */ get binaryType() { return this._binaryType; } set binaryType(type) { if (!BINARY_TYPES.includes(type)) return; this._binaryType = type; // // Allow to change `binaryType` on the fly. // if (this._receiver) this._receiver._binaryType = type; } /** * @type {Number} */ get bufferedAmount() { if (!this._socket) return this._bufferedAmount; return this._socket._writableState.length + this._sender._bufferedBytes; } /** * @type {String} */ get extensions() { return Object.keys(this._extensions).join(); } /** * @type {Boolean} */ get isPaused() { return this._paused; } /** * @type {Function} */ /* istanbul ignore next */ get onclose() { return null; } /** * @type {Function} */ /* istanbul ignore next */ get onerror() { return null; } /** * @type {Function} */ /* istanbul ignore next */ get onopen() { return null; } /** * @type {Function} */ /* istanbul ignore next */ get onmessage() { return null; } /** * @type {String} */ get protocol() { return this._protocol; } /** * @type {Number} */ get readyState() { return this._readyState; } /** * @type {String} */ get url() { return this._url; } /** * Set up the socket and the internal resources. * * @param {Duplex} socket The network socket between the server and client * @param {Buffer} head The first packet of the upgraded stream * @param {Object} options Options object * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted * multiple times in the same tick * @param {Function} [options.generateMask] The function used to generate the * masking key * @param {Number} [options.maxPayload=0] The maximum allowed message size * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or * not to skip UTF-8 validation for text and close messages * @private */ setSocket(socket, head, options) { const receiver = new Receiver({ allowSynchronousEvents: options.allowSynchronousEvents, binaryType: this.binaryType, extensions: this._extensions, isServer: this._isServer, maxPayload: options.maxPayload, skipUTF8Validation: options.skipUTF8Validation }); const sender = new Sender(socket, this._extensions, options.generateMask); this._receiver = receiver; this._sender = sender; this._socket = socket; receiver[kWebSocket] = this; sender[kWebSocket] = this; socket[kWebSocket] = this; receiver.on('conclude', receiverOnConclude); receiver.on('drain', receiverOnDrain); receiver.on('error', receiverOnError); receiver.on('message', receiverOnMessage); receiver.on('ping', receiverOnPing); receiver.on('pong', receiverOnPong); sender.onerror = senderOnError; // // These methods may not be available if `socket` is just a `Duplex`. // if (socket.setTimeout) socket.setTimeout(0); if (socket.setNoDelay) socket.setNoDelay(); if (head.length > 0) socket.unshift(head); socket.on('close', socketOnClose); socket.on('data', socketOnData); socket.on('end', socketOnEnd); socket.on('error', socketOnError); this._readyState = WebSocket.OPEN; this.emit('open'); } /** * Emit the `'close'` event. * * @private */ emitClose() { if (!this._socket) { this._readyState = WebSocket.CLOSED; this.emit('close', this._closeCode, this._closeMessage); return; } if (this._extensions[PerMessageDeflate.extensionName]) { this._extensions[PerMessageDeflate.extensionName].cleanup(); } this._receiver.removeAllListeners(); this._readyState = WebSocket.CLOSED; this.emit('close', this._closeCode, this._closeMessage); } /** * Start a closing handshake. * * +----------+ +-----------+ +----------+ * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - * | +----------+ +-----------+ +----------+ | * +----------+ +-----------+ | * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING * +----------+ +-----------+ | * | | | +---+ | * +------------------------+-->|fin| - - - - * | +---+ | +---+ * - - - - -|fin|<---------------------+ * +---+ * * @param {Number} [code] Status code explaining why the connection is closing * @param {(String|Buffer)} [data] The reason why the connection is * closing * @public */ close(code, data) { if (this.readyState === WebSocket.CLOSED) return; if (this.readyState === WebSocket.CONNECTING) { const msg = 'WebSocket was closed before the connection was established'; abortHandshake(this, this._req, msg); return; } if (this.readyState === WebSocket.CLOSING) { if ( this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted) ) { this._socket.end(); } return; } this._readyState = WebSocket.CLOSING; this._sender.close(code, data, !this._isServer, (err) => { // // This error is handled by the `'error'` listener on the socket. We only // want to know if the close frame has been sent here. // if (err) return; this._closeFrameSent = true; if ( this._closeFrameReceived || this._receiver._writableState.errorEmitted ) { this._socket.end(); } }); setCloseTimer(this); } /** * Pause the socket. * * @public */ pause() { if ( this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED ) { return; } this._paused = true; this._socket.pause(); } /** * Send a ping. * * @param {*} [data] The data to send * @param {Boolean} [mask] Indicates whether or not to mask `data` * @param {Function} [cb] Callback which is executed when the ping is sent * @public */ ping(data, mask, cb) { if (this.readyState === WebSocket.CONNECTING) { throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); } if (typeof data === 'function') { cb = data; data = mask = undefined; } else if (typeof mask === 'function') { cb = mask; mask = undefined; } if (typeof data === 'number') data = data.toString(); if (this.readyState !== WebSocket.OPEN) { sendAfterClose(this, data, cb); return; } if (mask === undefined) mask = !this._isServer; this._sender.ping(data || EMPTY_BUFFER, mask, cb); } /** * Send a pong. * * @param {*} [data] The data to send * @param {Boolean} [mask] Indicates whether or not to mask `data` * @param {Function} [cb] Callback which is executed when the pong is sent * @public */ pong(data, mask, cb) { if (this.readyState === WebSocket.CONNECTING) { throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); } if (typeof data === 'function') { cb = data; data = mask = undefined; } else if (typeof mask === 'function') { cb = mask; mask = undefined; } if (typeof data === 'number') data = data.toString(); if (this.readyState !== WebSocket.OPEN) { sendAfterClose(this, data, cb); return; } if (mask === undefined) mask = !this._isServer; this._sender.pong(data || EMPTY_BUFFER, mask, cb); } /** * Resume the socket. * * @public */ resume() { if ( this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED ) { return; } this._paused = false; if (!this._receiver._writableState.needDrain) this._socket.resume(); } /** * Send a data message. * * @param {*} data The message to send * @param {Object} [options] Options object * @param {Boolean} [options.binary] Specifies whether `data` is binary or * text * @param {Boolean} [options.compress] Specifies whether or not to compress * `data` * @param {Boolean} [options.fin=true] Specifies whether the fragment is the * last one * @param {Boolean} [options.mask] Specifies whether or not to mask `data` * @param {Function} [cb] Callback which is executed when data is written out * @public */ send(data, options, cb) { if (this.readyState === WebSocket.CONNECTING) { throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); } if (typeof options === 'function') { cb = options; options = {}; } if (typeof data === 'number') data = data.toString(); if (this.readyState !== WebSocket.OPEN) { sendAfterClose(this, data, cb); return; } const opts = { binary: typeof data !== 'string', mask: !this._isServer, compress: true, fin: true, ...options }; if (!this._extensions[PerMessageDeflate.extensionName]) { opts.compress = false; } this._sender.send(data || EMPTY_BUFFER, opts, cb); } /** * Forcibly close the connection. * * @public */ terminate() { if (this.readyState === WebSocket.CLOSED) return; if (this.readyState === WebSocket.CONNECTING) { const msg = 'WebSocket was closed before the connection was established'; abortHandshake(this, this._req, msg); return; } if (this._socket) { this._readyState = WebSocket.CLOSING; this._socket.destroy(); } } } /** * @constant {Number} CONNECTING * @memberof WebSocket */ Object.defineProperty(WebSocket, 'CONNECTING', { enumerable: true, value: readyStates.indexOf('CONNECTING') }); /** * @constant {Number} CONNECTING * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket.prototype, 'CONNECTING', { enumerable: true, value: readyStates.indexOf('CONNECTING') }); /** * @constant {Number} OPEN * @memberof WebSocket */ Object.defineProperty(WebSocket, 'OPEN', { enumerable: true, value: readyStates.indexOf('OPEN') }); /** * @constant {Number} OPEN * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket.prototype, 'OPEN', { enumerable: true, value: readyStates.indexOf('OPEN') }); /** * @constant {Number} CLOSING * @memberof WebSocket */ Object.defineProperty(WebSocket, 'CLOSING', { enumerable: true, value: readyStates.indexOf('CLOSING') }); /** * @constant {Number} CLOSING * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket.prototype, 'CLOSING', { enumerable: true, value: readyStates.indexOf('CLOSING') }); /** * @constant {Number} CLOSED * @memberof WebSocket */ Object.defineProperty(WebSocket, 'CLOSED', { enumerable: true, value: readyStates.indexOf('CLOSED') }); /** * @constant {Number} CLOSED * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket.prototype, 'CLOSED', { enumerable: true, value: readyStates.indexOf('CLOSED') }); [ 'binaryType', 'bufferedAmount', 'extensions', 'isPaused', 'protocol', 'readyState', 'url' ].forEach((property) => { Object.defineProperty(WebSocket.prototype, property, { enumerable: true }); }); // // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes. // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface // ['open', 'error', 'close', 'message'].forEach((method) => { Object.defineProperty(WebSocket.prototype, `on${method}`, { enumerable: true, get() { for (const listener of this.listeners(method)) { if (listener[kForOnEventAttribute]) return listener[kListener]; } return null; }, set(handler) { for (const listener of this.listeners(method)) { if (listener[kForOnEventAttribute]) { this.removeListener(method, listener); break; } } if (typeof handler !== 'function') return; this.addEventListener(method, handler, { [kForOnEventAttribute]: true }); } }); }); WebSocket.prototype.addEventListener = addEventListener; WebSocket.prototype.removeEventListener = removeEventListener; websocket = WebSocket; /** * Initialize a WebSocket client. * * @param {WebSocket} websocket The client to initialize * @param {(String|URL)} address The URL to which to connect * @param {Array} protocols The subprotocols * @param {Object} [options] Connection options * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple * times in the same tick * @param {Boolean} [options.autoPong=true] Specifies whether or not to * automatically send a pong in response to a ping * @param {Function} [options.finishRequest] A function which can be used to * customize the headers of each http request before it is sent * @param {Boolean} [options.followRedirects=false] Whether or not to follow * redirects * @param {Function} [options.generateMask] The function used to generate the * masking key * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the * handshake request * @param {Number} [options.maxPayload=104857600] The maximum allowed message * size * @param {Number} [options.maxRedirects=10] The maximum number of redirects * allowed * @param {String} [options.origin] Value of the `Origin` or * `Sec-WebSocket-Origin` header * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable * permessage-deflate * @param {Number} [options.protocolVersion=13] Value of the * `Sec-WebSocket-Version` header * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or * not to skip UTF-8 validation for text and close messages * @private */ function initAsClient(websocket, address, protocols, options) { const opts = { allowSynchronousEvents: true, autoPong: true, protocolVersion: protocolVersions[1], maxPayload: 100 * 1024 * 1024, skipUTF8Validation: false, perMessageDeflate: true, followRedirects: false, maxRedirects: 10, ...options, socketPath: undefined, hostname: undefined, protocol: undefined, timeout: undefined, method: 'GET', host: undefined, path: undefined, port: undefined }; websocket._autoPong = opts.autoPong; if (!protocolVersions.includes(opts.protocolVersion)) { throw new RangeError( `Unsupported protocol version: ${opts.protocolVersion} ` + `(supported versions: ${protocolVersions.join(', ')})` ); } let parsedUrl; if (address instanceof URL) { parsedUrl = address; } else { try { parsedUrl = new URL(address); } catch (e) { throw new SyntaxError(`Invalid URL: ${address}`); } } if (parsedUrl.protocol === 'http:') { parsedUrl.protocol = 'ws:'; } else if (parsedUrl.protocol === 'https:') { parsedUrl.protocol = 'wss:'; } websocket._url = parsedUrl.href; const isSecure = parsedUrl.protocol === 'wss:'; const isIpcUrl = parsedUrl.protocol === 'ws+unix:'; let invalidUrlMessage; if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) { invalidUrlMessage = 'The URL\'s protocol must be one of "ws:", "wss:", ' + '"http:", "https", or "ws+unix:"'; } else if (isIpcUrl && !parsedUrl.pathname) { invalidUrlMessage = "The URL's pathname is empty"; } else if (parsedUrl.hash) { invalidUrlMessage = 'The URL contains a fragment identifier'; } if (invalidUrlMessage) { const err = new SyntaxError(invalidUrlMessage); if (websocket._redirects === 0) { throw err; } else { emitErrorAndClose(websocket, err); return; } } const defaultPort = isSecure ? 443 : 80; const key = randomBytes(16).toString('base64'); const request = isSecure ? https.request : http.request; const protocolSet = new Set(); let perMessageDeflate; opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect); opts.defaultPort = opts.defaultPort || defaultPort; opts.port = parsedUrl.port || defaultPort; opts.host = parsedUrl.hostname.startsWith('[') ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; opts.headers = { ...opts.headers, 'Sec-WebSocket-Version': opts.protocolVersion, 'Sec-WebSocket-Key': key, Connection: 'Upgrade', Upgrade: 'websocket' }; opts.path = parsedUrl.pathname + parsedUrl.search; opts.timeout = opts.handshakeTimeout; if (opts.perMessageDeflate) { perMessageDeflate = new PerMessageDeflate( opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, false, opts.maxPayload ); opts.headers['Sec-WebSocket-Extensions'] = format({ [PerMessageDeflate.extensionName]: perMessageDeflate.offer() }); } if (protocols.length) { for (const protocol of protocols) { if ( typeof protocol !== 'string' || !subprotocolRegex.test(protocol) || protocolSet.has(protocol) ) { throw new SyntaxError( 'An invalid or duplicated subprotocol was specified' ); } protocolSet.add(protocol); } opts.headers['Sec-WebSocket-Protocol'] = protocols.join(','); } if (opts.origin) { if (opts.protocolVersion < 13) { opts.headers['Sec-WebSocket-Origin'] = opts.origin; } else { opts.headers.Origin = opts.origin; } } if (parsedUrl.username || parsedUrl.password) { opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; } if (isIpcUrl) { const parts = opts.path.split(':'); opts.socketPath = parts[0]; opts.path = parts[1]; } let req; if (opts.followRedirects) { if (websocket._redirects === 0) { websocket._originalIpc = isIpcUrl; websocket._originalSecure = isSecure; websocket._originalHostOrSocketPath = isIpcUrl ? opts.socketPath : parsedUrl.host; const headers = options && options.headers; // // Shallow copy the user provided options so that headers can be changed // without mutating the original object. // options = { ...options, headers: {} }; if (headers) { for (const [key, value] of Object.entries(headers)) { options.headers[key.toLowerCase()] = value; } } } else if (websocket.listenerCount('redirect') === 0) { const isSameHost = isIpcUrl ? websocket._originalIpc ? opts.socketPath === websocket._originalHostOrSocketPath : false : websocket._originalIpc ? false : parsedUrl.host === websocket._originalHostOrSocketPath; if (!isSameHost || (websocket._originalSecure && !isSecure)) { // // Match curl 7.77.0 behavior and drop the following headers. These // headers are also dropped when following a redirect to a subdomain. // delete opts.headers.authorization; delete opts.headers.cookie; if (!isSameHost) delete opts.headers.host; opts.auth = undefined; } } // // Match curl 7.77.0 behavior and make the first `Authorization` header win. // If the `Authorization` header is set, then there is nothing to do as it // will take precedence. // if (opts.auth && !options.headers.authorization) { options.headers.authorization = 'Basic ' + Buffer.from(opts.auth).toString('base64'); } req = websocket._req = request(opts); if (websocket._redirects) { // // Unlike what is done for the `'upgrade'` event, no early exit is // triggered here if the user calls `websocket.close()` or // `websocket.terminate()` from a listener of the `'redirect'` event. This // is because the user can also call `request.destroy()` with an error // before calling `websocket.close()` or `websocket.terminate()` and this // would result in an error being emitted on the `request` object with no // `'error'` event listeners attached. // websocket.emit('redirect', websocket.url, req); } } else { req = websocket._req = request(opts); } if (opts.timeout) { req.on('timeout', () => { abortHandshake(websocket, req, 'Opening handshake has timed out'); }); } req.on('error', (err) => { if (req === null || req[kAborted]) return; req = websocket._req = null; emitErrorAndClose(websocket, err); }); req.on('response', (res) => { const location = res.headers.location; const statusCode = res.statusCode; if ( location && opts.followRedirects && statusCode >= 300 && statusCode < 400 ) { if (++websocket._redirects > opts.maxRedirects) { abortHandshake(websocket, req, 'Maximum redirects exceeded'); return; } req.abort(); let addr; try { addr = new URL(location, address); } catch (e) { const err = new SyntaxError(`Invalid URL: ${location}`); emitErrorAndClose(websocket, err); return; } initAsClient(websocket, addr, protocols, options); } else if (!websocket.emit('unexpected-response', req, res)) { abortHandshake( websocket, req, `Unexpected server response: ${res.statusCode}` ); } }); req.on('upgrade', (res, socket, head) => { websocket.emit('upgrade', res); // // The user may have closed the connection from a listener of the // `'upgrade'` event. // if (websocket.readyState !== WebSocket.CONNECTING) return; req = websocket._req = null; const upgrade = res.headers.upgrade; if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') { abortHandshake(websocket, socket, 'Invalid Upgrade header'); return; } const digest = createHash('sha1') .update(key + GUID) .digest('base64'); if (res.headers['sec-websocket-accept'] !== digest) { abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header'); return; } const serverProt = res.headers['sec-websocket-protocol']; let protError; if (serverProt !== undefined) { if (!protocolSet.size) { protError = 'Server sent a subprotocol but none was requested'; } else if (!protocolSet.has(serverProt)) { protError = 'Server sent an invalid subprotocol'; } } else if (protocolSet.size) { protError = 'Server sent no subprotocol'; } if (protError) { abortHandshake(websocket, socket, protError); return; } if (serverProt) websocket._protocol = serverProt; const secWebSocketExtensions = res.headers['sec-websocket-extensions']; if (secWebSocketExtensions !== undefined) { if (!perMessageDeflate) { const message = 'Server sent a Sec-WebSocket-Extensions header but no extension ' + 'was requested'; abortHandshake(websocket, socket, message); return; } let extensions; try { extensions = parse(secWebSocketExtensions); } catch (err) { const message = 'Invalid Sec-WebSocket-Extensions header'; abortHandshake(websocket, socket, message); return; } const extensionNames = Object.keys(extensions); if ( extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName ) { const message = 'Server indicated an extension that was not requested'; abortHandshake(websocket, socket, message); return; } try { perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); } catch (err) { const message = 'Invalid Sec-WebSocket-Extensions header'; abortHandshake(websocket, socket, message); return; } websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; } websocket.setSocket(socket, head, { allowSynchronousEvents: opts.allowSynchronousEvents, generateMask: opts.generateMask, maxPayload: opts.maxPayload, skipUTF8Validation: opts.skipUTF8Validation }); }); if (opts.finishRequest) { opts.finishRequest(req, websocket); } else { req.end(); } } /** * Emit the `'error'` and `'close'` events. * * @param {WebSocket} websocket The WebSocket instance * @param {Error} The error to emit * @private */ function emitErrorAndClose(websocket, err) { websocket._readyState = WebSocket.CLOSING; // // The following assignment is practically useless and is done only for // consistency. // websocket._errorEmitted = true; websocket.emit('error', err); websocket.emitClose(); } /** * Create a `net.Socket` and initiate a connection. * * @param {Object} options Connection options * @return {net.Socket} The newly created socket used to start the connection * @private */ function netConnect(options) { options.path = options.socketPath; return net.connect(options); } /** * Create a `tls.TLSSocket` and initiate a connection. * * @param {Object} options Connection options * @return {tls.TLSSocket} The newly created socket used to start the connection * @private */ function tlsConnect(options) { options.path = undefined; if (!options.servername && options.servername !== '') { options.servername = net.isIP(options.host) ? '' : options.host; } return tls.connect(options); } /** * Abort the handshake and emit an error. * * @param {WebSocket} websocket The WebSocket instance * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to * abort or the socket to destroy * @param {String} message The error message * @private */ function abortHandshake(websocket, stream, message) { websocket._readyState = WebSocket.CLOSING; const err = new Error(message); Error.captureStackTrace(err, abortHandshake); if (stream.setHeader) { stream[kAborted] = true; stream.abort(); if (stream.socket && !stream.socket.destroyed) { // // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if // called after the request completed. See // https://github.com/websockets/ws/issues/1869. // stream.socket.destroy(); } process.nextTick(emitErrorAndClose, websocket, err); } else { stream.destroy(err); stream.once('error', websocket.emit.bind(websocket, 'error')); stream.once('close', websocket.emitClose.bind(websocket)); } } /** * Handle cases where the `ping()`, `pong()`, or `send()` methods are called * when the `readyState` attribute is `CLOSING` or `CLOSED`. * * @param {WebSocket} websocket The WebSocket instance * @param {*} [data] The data to send * @param {Function} [cb] Callback * @private */ function sendAfterClose(websocket, data, cb) { if (data) { const length = isBlob(data) ? data.size : toBuffer(data).length; // // The `_bufferedAmount` property is used only when the peer is a client and // the opening handshake fails. Under these circumstances, in fact, the // `setSocket()` method is not called, so the `_socket` and `_sender` // properties are set to `null`. // if (websocket._socket) websocket._sender._bufferedBytes += length; else websocket._bufferedAmount += length; } if (cb) { const err = new Error( `WebSocket is not open: readyState ${websocket.readyState} ` + `(${readyStates[websocket.readyState]})` ); process.nextTick(cb, err); } } /** * The listener of the `Receiver` `'conclude'` event. * * @param {Number} code The status code * @param {Buffer} reason The reason for closing * @private */ function receiverOnConclude(code, reason) { const websocket = this[kWebSocket]; websocket._closeFrameReceived = true; websocket._closeMessage = reason; websocket._closeCode = code; if (websocket._socket[kWebSocket] === undefined) return; websocket._socket.removeListener('data', socketOnData); process.nextTick(resume, websocket._socket); if (code === 1005) websocket.close(); else websocket.close(code, reason); } /** * The listener of the `Receiver` `'drain'` event. * * @private */ function receiverOnDrain() { const websocket = this[kWebSocket]; if (!websocket.isPaused) websocket._socket.resume(); } /** * The listener of the `Receiver` `'error'` event. * * @param {(RangeError|Error)} err The emitted error * @private */ function receiverOnError(err) { const websocket = this[kWebSocket]; if (websocket._socket[kWebSocket] !== undefined) { websocket._socket.removeListener('data', socketOnData); // // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See // https://github.com/websockets/ws/issues/1940. // process.nextTick(resume, websocket._socket); websocket.close(err[kStatusCode]); } if (!websocket._errorEmitted) { websocket._errorEmitted = true; websocket.emit('error', err); } } /** * The listener of the `Receiver` `'finish'` event. * * @private */ function receiverOnFinish() { this[kWebSocket].emitClose(); } /** * The listener of the `Receiver` `'message'` event. * * @param {Buffer|ArrayBuffer|Buffer[])} data The message * @param {Boolean} isBinary Specifies whether the message is binary or not * @private */ function receiverOnMessage(data, isBinary) { this[kWebSocket].emit('message', data, isBinary); } /** * The listener of the `Receiver` `'ping'` event. * * @param {Buffer} data The data included in the ping frame * @private */ function receiverOnPing(data) { const websocket = this[kWebSocket]; if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP); websocket.emit('ping', data); } /** * The listener of the `Receiver` `'pong'` event. * * @param {Buffer} data The data included in the pong frame * @private */ function receiverOnPong(data) { this[kWebSocket].emit('pong', data); } /** * Resume a readable stream * * @param {Readable} stream The readable stream * @private */ function resume(stream) { stream.resume(); } /** * The `Sender` error event handler. * * @param {Error} The error * @private */ function senderOnError(err) { const websocket = this[kWebSocket]; if (websocket.readyState === WebSocket.CLOSED) return; if (websocket.readyState === WebSocket.OPEN) { websocket._readyState = WebSocket.CLOSING; setCloseTimer(websocket); } // // `socket.end()` is used instead of `socket.destroy()` to allow the other // peer to finish sending queued data. There is no need to set a timer here // because `CLOSING` means that it is already set or not needed. // this._socket.end(); if (!websocket._errorEmitted) { websocket._errorEmitted = true; websocket.emit('error', err); } } /** * Set a timer to destroy the underlying raw socket of a WebSocket. * * @param {WebSocket} websocket The WebSocket instance * @private */ function setCloseTimer(websocket) { websocket._closeTimer = setTimeout( websocket._socket.destroy.bind(websocket._socket), closeTimeout ); } /** * The listener of the socket `'close'` event. * * @private */ function socketOnClose() { const websocket = this[kWebSocket]; this.removeListener('close', socketOnClose); this.removeListener('data', socketOnData); this.removeListener('end', socketOnEnd); websocket._readyState = WebSocket.CLOSING; let chunk; // // The close frame might not have been received or the `'end'` event emitted, // for example, if the socket was destroyed due to an error. Ensure that the // `receiver` stream is closed after writing any remaining buffered data to // it. If the readable side of the socket is in flowing mode then there is no // buffered data as everything has been already written and `readable.read()` // will return `null`. If instead, the socket is paused, any possible buffered // data will be read as a single chunk. // if ( !this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && (chunk = websocket._socket.read()) !== null ) { websocket._receiver.write(chunk); } websocket._receiver.end(); this[kWebSocket] = undefined; clearTimeout(websocket._closeTimer); if ( websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted ) { websocket.emitClose(); } else { websocket._receiver.on('error', receiverOnFinish); websocket._receiver.on('finish', receiverOnFinish); } } /** * The listener of the socket `'data'` event. * * @param {Buffer} chunk A chunk of data * @private */ function socketOnData(chunk) { if (!this[kWebSocket]._receiver.write(chunk)) { this.pause(); } } /** * The listener of the socket `'end'` event. * * @private */ function socketOnEnd() { const websocket = this[kWebSocket]; websocket._readyState = WebSocket.CLOSING; websocket._receiver.end(); this.end(); } /** * The listener of the socket `'error'` event. * * @private */ function socketOnError() { const websocket = this[kWebSocket]; this.removeListener('error', socketOnError); this.on('error', NOOP); if (websocket) { websocket._readyState = WebSocket.CLOSING; this.destroy(); } } return websocket; } requireWebsocket(); var subprotocol; var hasRequiredSubprotocol; function requireSubprotocol () { if (hasRequiredSubprotocol) return subprotocol; hasRequiredSubprotocol = 1; const { tokenChars } = requireValidation(); /** * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names. * * @param {String} header The field value of the header * @return {Set} The subprotocol names * @public */ function parse(header) { const protocols = new Set(); let start = -1; let end = -1; let i = 0; for (i; i < header.length; i++) { const code = header.charCodeAt(i); if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; } else if ( i !== 0 && (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ ) { if (end === -1 && start !== -1) end = i; } else if (code === 0x2c /* ',' */) { if (start === -1) { throw new SyntaxError(`Unexpected character at index ${i}`); } if (end === -1) end = i; const protocol = header.slice(start, end); if (protocols.has(protocol)) { throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); } protocols.add(protocol); start = end = -1; } else { throw new SyntaxError(`Unexpected character at index ${i}`); } } if (start === -1 || end !== -1) { throw new SyntaxError('Unexpected end of input'); } const protocol = header.slice(start, i); if (protocols.has(protocol)) { throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); } protocols.add(protocol); return protocols; } subprotocol = { parse }; return subprotocol; } /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */ var websocketServer; var hasRequiredWebsocketServer; function requireWebsocketServer () { if (hasRequiredWebsocketServer) return websocketServer; hasRequiredWebsocketServer = 1; const EventEmitter = require$$0$3; const http = require$$2; const { createHash } = require$$1; const extension = requireExtension(); const PerMessageDeflate = requirePermessageDeflate(); const subprotocol = requireSubprotocol(); const WebSocket = requireWebsocket(); const { GUID, kWebSocket } = requireConstants$1(); const keyRegex = /^[+/0-9A-Za-z]{22}==$/; const RUNNING = 0; const CLOSING = 1; const CLOSED = 2; /** * Class representing a WebSocket server. * * @extends EventEmitter */ class WebSocketServer extends EventEmitter { /** * Create a `WebSocketServer` instance. * * @param {Object} options Configuration options * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted * multiple times in the same tick * @param {Boolean} [options.autoPong=true] Specifies whether or not to * automatically send a pong in response to a ping * @param {Number} [options.backlog=511] The maximum length of the queue of * pending connections * @param {Boolean} [options.clientTracking=true] Specifies whether or not to * track clients * @param {Function} [options.handleProtocols] A hook to handle protocols * @param {String} [options.host] The hostname where to bind the server * @param {Number} [options.maxPayload=104857600] The maximum allowed message * size * @param {Boolean} [options.noServer=false] Enable no server mode * @param {String} [options.path] Accept only connections matching this path * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable * permessage-deflate * @param {Number} [options.port] The port where to bind the server * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S * server to use * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or * not to skip UTF-8 validation for text and close messages * @param {Function} [options.verifyClient] A hook to reject connections * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` * class to use. It must be the `WebSocket` class or class that extends it * @param {Function} [callback] A listener for the `listening` event */ constructor(options, callback) { super(); options = { allowSynchronousEvents: true, autoPong: true, maxPayload: 100 * 1024 * 1024, skipUTF8Validation: false, perMessageDeflate: false, handleProtocols: null, clientTracking: true, verifyClient: null, noServer: false, backlog: null, // use default (511 as implemented in net.js) server: null, host: null, path: null, port: null, WebSocket, ...options }; if ( (options.port == null && !options.server && !options.noServer) || (options.port != null && (options.server || options.noServer)) || (options.server && options.noServer) ) { throw new TypeError( 'One and only one of the "port", "server", or "noServer" options ' + 'must be specified' ); } if (options.port != null) { this._server = http.createServer((req, res) => { const body = http.STATUS_CODES[426]; res.writeHead(426, { 'Content-Length': body.length, 'Content-Type': 'text/plain' }); res.end(body); }); this._server.listen( options.port, options.host, options.backlog, callback ); } else if (options.server) { this._server = options.server; } if (this._server) { const emitConnection = this.emit.bind(this, 'connection'); this._removeListeners = addListeners(this._server, { listening: this.emit.bind(this, 'listening'), error: this.emit.bind(this, 'error'), upgrade: (req, socket, head) => { this.handleUpgrade(req, socket, head, emitConnection); } }); } if (options.perMessageDeflate === true) options.perMessageDeflate = {}; if (options.clientTracking) { this.clients = new Set(); this._shouldEmitClose = false; } this.options = options; this._state = RUNNING; } /** * Returns the bound address, the address family name, and port of the server * as reported by the operating system if listening on an IP socket. * If the server is listening on a pipe or UNIX domain socket, the name is * returned as a string. * * @return {(Object|String|null)} The address of the server * @public */ address() { if (this.options.noServer) { throw new Error('The server is operating in "noServer" mode'); } if (!this._server) return null; return this._server.address(); } /** * Stop the server from accepting new connections and emit the `'close'` event * when all existing connections are closed. * * @param {Function} [cb] A one-time listener for the `'close'` event * @public */ close(cb) { if (this._state === CLOSED) { if (cb) { this.once('close', () => { cb(new Error('The server is not running')); }); } process.nextTick(emitClose, this); return; } if (cb) this.once('close', cb); if (this._state === CLOSING) return; this._state = CLOSING; if (this.options.noServer || this.options.server) { if (this._server) { this._removeListeners(); this._removeListeners = this._server = null; } if (this.clients) { if (!this.clients.size) { process.nextTick(emitClose, this); } else { this._shouldEmitClose = true; } } else { process.nextTick(emitClose, this); } } else { const server = this._server; this._removeListeners(); this._removeListeners = this._server = null; // // The HTTP/S server was created internally. Close it, and rely on its // `'close'` event. // server.close(() => { emitClose(this); }); } } /** * See if a given request should be handled by this server instance. * * @param {http.IncomingMessage} req Request object to inspect * @return {Boolean} `true` if the request is valid, else `false` * @public */ shouldHandle(req) { if (this.options.path) { const index = req.url.indexOf('?'); const pathname = index !== -1 ? req.url.slice(0, index) : req.url; if (pathname !== this.options.path) return false; } return true; } /** * Handle a HTTP Upgrade request. * * @param {http.IncomingMessage} req The request object * @param {Duplex} socket The network socket between the server and client * @param {Buffer} head The first packet of the upgraded stream * @param {Function} cb Callback * @public */ handleUpgrade(req, socket, head, cb) { socket.on('error', socketOnError); const key = req.headers['sec-websocket-key']; const upgrade = req.headers.upgrade; const version = +req.headers['sec-websocket-version']; if (req.method !== 'GET') { const message = 'Invalid HTTP method'; abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); return; } if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') { const message = 'Invalid Upgrade header'; abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } if (key === undefined || !keyRegex.test(key)) { const message = 'Missing or invalid Sec-WebSocket-Key header'; abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } if (version !== 8 && version !== 13) { const message = 'Missing or invalid Sec-WebSocket-Version header'; abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } if (!this.shouldHandle(req)) { abortHandshake(socket, 400); return; } const secWebSocketProtocol = req.headers['sec-websocket-protocol']; let protocols = new Set(); if (secWebSocketProtocol !== undefined) { try { protocols = subprotocol.parse(secWebSocketProtocol); } catch (err) { const message = 'Invalid Sec-WebSocket-Protocol header'; abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } } const secWebSocketExtensions = req.headers['sec-websocket-extensions']; const extensions = {}; if ( this.options.perMessageDeflate && secWebSocketExtensions !== undefined ) { const perMessageDeflate = new PerMessageDeflate( this.options.perMessageDeflate, true, this.options.maxPayload ); try { const offers = extension.parse(secWebSocketExtensions); if (offers[PerMessageDeflate.extensionName]) { perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); extensions[PerMessageDeflate.extensionName] = perMessageDeflate; } } catch (err) { const message = 'Invalid or unacceptable Sec-WebSocket-Extensions header'; abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } } // // Optionally call external client verification handler. // if (this.options.verifyClient) { const info = { origin: req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`], secure: !!(req.socket.authorized || req.socket.encrypted), req }; if (this.options.verifyClient.length === 2) { this.options.verifyClient(info, (verified, code, message, headers) => { if (!verified) { return abortHandshake(socket, code || 401, message, headers); } this.completeUpgrade( extensions, key, protocols, req, socket, head, cb ); }); return; } if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); } this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); } /** * Upgrade the connection to WebSocket. * * @param {Object} extensions The accepted extensions * @param {String} key The value of the `Sec-WebSocket-Key` header * @param {Set} protocols The subprotocols * @param {http.IncomingMessage} req The request object * @param {Duplex} socket The network socket between the server and client * @param {Buffer} head The first packet of the upgraded stream * @param {Function} cb Callback * @throws {Error} If called more than once with the same socket * @private */ completeUpgrade(extensions, key, protocols, req, socket, head, cb) { // // Destroy the socket if the client has already sent a FIN packet. // if (!socket.readable || !socket.writable) return socket.destroy(); if (socket[kWebSocket]) { throw new Error( 'server.handleUpgrade() was called more than once with the same ' + 'socket, possibly due to a misconfiguration' ); } if (this._state > RUNNING) return abortHandshake(socket, 503); const digest = createHash('sha1') .update(key + GUID) .digest('base64'); const headers = [ 'HTTP/1.1 101 Switching Protocols', 'Upgrade: websocket', 'Connection: Upgrade', `Sec-WebSocket-Accept: ${digest}` ]; const ws = new this.options.WebSocket(null, undefined, this.options); if (protocols.size) { // // Optionally call external protocol selection handler. // const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; if (protocol) { headers.push(`Sec-WebSocket-Protocol: ${protocol}`); ws._protocol = protocol; } } if (extensions[PerMessageDeflate.extensionName]) { const params = extensions[PerMessageDeflate.extensionName].params; const value = extension.format({ [PerMessageDeflate.extensionName]: [params] }); headers.push(`Sec-WebSocket-Extensions: ${value}`); ws._extensions = extensions; } // // Allow external modification/inspection of handshake headers. // this.emit('headers', headers, req); socket.write(headers.concat('\r\n').join('\r\n')); socket.removeListener('error', socketOnError); ws.setSocket(socket, head, { allowSynchronousEvents: this.options.allowSynchronousEvents, maxPayload: this.options.maxPayload, skipUTF8Validation: this.options.skipUTF8Validation }); if (this.clients) { this.clients.add(ws); ws.on('close', () => { this.clients.delete(ws); if (this._shouldEmitClose && !this.clients.size) { process.nextTick(emitClose, this); } }); } cb(ws, req); } } websocketServer = WebSocketServer; /** * Add event listeners on an `EventEmitter` using a map of * pairs. * * @param {EventEmitter} server The event emitter * @param {Object.} map The listeners to add * @return {Function} A function that will remove the added listeners when * called * @private */ function addListeners(server, map) { for (const event of Object.keys(map)) server.on(event, map[event]); return function removeListeners() { for (const event of Object.keys(map)) { server.removeListener(event, map[event]); } }; } /** * Emit a `'close'` event on an `EventEmitter`. * * @param {EventEmitter} server The event emitter * @private */ function emitClose(server) { server._state = CLOSED; server.emit('close'); } /** * Handle socket errors. * * @private */ function socketOnError() { this.destroy(); } /** * Close the connection when preconditions are not fulfilled. * * @param {Duplex} socket The socket of the upgrade request * @param {Number} code The HTTP response status code * @param {String} [message] The HTTP response body * @param {Object} [headers] Additional HTTP response headers * @private */ function abortHandshake(socket, code, message, headers) { // // The socket is writable unless the user destroyed or ended it before calling // `server.handleUpgrade()` or in the `verifyClient` function, which is a user // error. Handling this does not make much sense as the worst that can happen // is that some of the data written by the user might be discarded due to the // call to `socket.end()` below, which triggers an `'error'` event that in // turn causes the socket to be destroyed. // message = message || http.STATUS_CODES[code]; headers = { Connection: 'close', 'Content-Type': 'text/html', 'Content-Length': Buffer.byteLength(message), ...headers }; socket.once('finish', socket.destroy); socket.end( `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + Object.keys(headers) .map((h) => `${h}: ${headers[h]}`) .join('\r\n') + '\r\n\r\n' + message ); } /** * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least * one listener for it, otherwise call `abortHandshake()`. * * @param {WebSocketServer} server The WebSocket server * @param {http.IncomingMessage} req The request object * @param {Duplex} socket The socket of the upgrade request * @param {Number} code The HTTP response status code * @param {String} message The HTTP response body * @private */ function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) { if (server.listenerCount('wsClientError')) { const err = new Error(message); Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); server.emit('wsClientError', err, socket, req); } else { abortHandshake(socket, code, message); } } return websocketServer; } var websocketServerExports = requireWebsocketServer(); var WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServerExports); async function getModuleGraph(ctx, projectName, id, browser = false) { const graph = {}; const externalized = /* @__PURE__ */ new Set(); const inlined = /* @__PURE__ */ new Set(); const project = ctx.getProjectByName(projectName); async function get(mod, seen = /* @__PURE__ */ new Map()) { if (!mod || !mod.id) { return; } if (mod.id === "\0@vitest/browser/context") { return; } if (seen.has(mod)) { return seen.get(mod); } let id2 = clearId(mod.id); seen.set(mod, id2); const rewrote = browser ? mod.file?.includes(project.browser.vite.config.cacheDir) ? mod.id : false : await project.vitenode.shouldExternalize(id2); if (rewrote) { id2 = rewrote; externalized.add(id2); seen.set(mod, id2); } else { inlined.add(id2); } const mods = Array.from(mod.importedModules).filter( (i) => i.id && !i.id.includes("/vitest/dist/") ); graph[id2] = (await Promise.all(mods.map((m) => get(m, seen)))).filter( Boolean ); return id2; } if (browser && project.browser) { await get(project.browser.vite.moduleGraph.getModuleById(id)); } else { await get(project.server.moduleGraph.getModuleById(id)); } return { graph, externalized: Array.from(externalized), inlined: Array.from(inlined) }; } function clearId(id) { return id?.replace(/\?v=\w+$/, "") || ""; } function cloneByOwnProperties(value) { return Object.getOwnPropertyNames(value).reduce( (clone, prop) => ({ ...clone, [prop]: value[prop] }), {} ); } function stringifyReplace(key, value) { if (value instanceof Error) { const cloned = cloneByOwnProperties(value); return { name: value.name, message: value.message, stack: value.stack, ...cloned }; } else { return value; } } function setup(ctx, _server) { const wss = new WebSocketServer({ noServer: true }); const clients = /* @__PURE__ */ new Map(); const server = _server || ctx.server; server.httpServer?.on("upgrade", (request, socket, head) => { if (!request.url) { return; } const { pathname } = new URL(request.url, "http://localhost"); if (pathname !== API_PATH) { return; } if (!isValidApiRequest(ctx.config, request)) { socket.destroy(); return; } wss.handleUpgrade(request, socket, head, (ws) => { wss.emit("connection", ws, request); setupClient(ws); }); }); function setupClient(ws) { const rpc = createBirpc( { async onTaskUpdate(packs) { ctx.state.updateTasks(packs); await ctx.report("onTaskUpdate", packs); }, getFiles() { return ctx.state.getFiles(); }, getPaths() { return ctx.state.getPaths(); }, async readTestFile(id) { if (!ctx.state.filesMap.has(id) || !existsSync(id)) { return null; } return promises.readFile(id, "utf-8"); }, async saveTestFile(id, content) { if (!ctx.state.filesMap.has(id) || !existsSync(id)) { throw new Error( `Test file "${id}" was not registered, so it cannot be updated using the API.` ); } return promises.writeFile(id, content, "utf-8"); }, async rerun(files) { await ctx.rerunFiles(files); }, getConfig() { return ctx.getCoreWorkspaceProject().getSerializableConfig(); }, async getTransformResult(projectName, id, browser = false) { const project = ctx.getProjectByName(projectName); const result = browser ? await project.browser.vite.transformRequest(id) : await project.vitenode.transformRequest(id); if (result) { try { result.source = result.source || await promises.readFile(id, "utf-8"); } catch { } return result; } }, async getModuleGraph(project, id, browser) { return getModuleGraph(ctx, project, id, browser); }, updateSnapshot(file) { if (!file) { return ctx.updateSnapshot(); } return ctx.updateSnapshot([file.filepath]); }, getUnhandledErrors() { return ctx.state.getUnhandledErrors(); }, async getTestFiles() { const spec = await ctx.globTestSpecs(); return spec.map((spec2) => [ { name: spec2.project.config.name, root: spec2.project.config.root }, spec2.moduleId, { pool: spec2.pool } ]); } }, { post: (msg) => ws.send(msg), on: (fn) => ws.on("message", fn), eventNames: [ "onUserConsoleLog", "onFinished", "onFinishedReportCoverage", "onCollected", "onTaskUpdate" ], serialize: (data) => stringify(data, stringifyReplace), deserialize: parse, onTimeoutError(functionName) { throw new Error(`[vitest-api]: Timeout calling "${functionName}"`); } } ); clients.set(ws, rpc); ws.on("close", () => { clients.delete(ws); }); } ctx.reporters.push(new WebSocketReporter(ctx, wss, clients)); } class WebSocketReporter { constructor(ctx, wss, clients) { this.ctx = ctx; this.wss = wss; this.clients = clients; } onCollected(files) { if (this.clients.size === 0) { return; } this.clients.forEach((client) => { client.onCollected?.(files)?.catch?.(noop); }); } onSpecsCollected(specs) { if (this.clients.size === 0) { return; } this.clients.forEach((client) => { client.onSpecsCollected?.(specs)?.catch?.(noop); }); } async onTaskUpdate(packs) { if (this.clients.size === 0) { return; } packs.forEach(([taskId, result]) => { const project = this.ctx.getProjectByTaskId(taskId); const task = this.ctx.state.idMap.get(taskId); const isBrowser = task && task.file.pool === "browser"; result?.errors?.forEach((error) => { if (isPrimitive(error)) { return; } const stacks = isBrowser ? project.browser?.parseErrorStacktrace(error) : parseErrorStacktrace(error); error.stacks = stacks; }); }); this.clients.forEach((client) => { client.onTaskUpdate?.(packs)?.catch?.(noop); }); } onFinished(files, errors) { this.clients.forEach((client) => { client.onFinished?.(files, errors)?.catch?.(noop); }); } onFinishedReportCoverage() { this.clients.forEach((client) => { client.onFinishedReportCoverage?.()?.catch?.(noop); }); } onUserConsoleLog(log) { this.clients.forEach((client) => { client.onUserConsoleLog?.(log)?.catch?.(noop); }); } } var setup$1 = /*#__PURE__*/Object.freeze({ __proto__: null, WebSocketReporter: WebSocketReporter, setup: setup }); class FilesNotFoundError extends Error { code = "VITEST_FILES_NOT_FOUND"; constructor(mode) { super(`No ${mode} files found`); } } class GitNotFoundError extends Error { code = "VITEST_GIT_NOT_FOUND"; constructor() { super("Could not find Git root. Have you initialized git with `git init`?"); } } const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); class VitestPackageInstaller { isPackageExists(name, options) { return isPackageExists(name, options); } async ensureInstalled(dependency, root, version) { if (process.env.VITEST_SKIP_INSTALL_CHECKS) { return true; } if (process.versions.pnp) { const targetRequire = createRequire(__dirname); try { targetRequire.resolve(dependency, { paths: [root, __dirname] }); return true; } catch { } } if (/* @__PURE__ */ isPackageExists(dependency, { paths: [root, __dirname] })) { return true; } const promptInstall = !isCI && process.stdout.isTTY; process.stderr.write( c.red( `${c.inverse( c.red(" MISSING DEPENDENCY ") )} Cannot find dependency '${dependency}' ` ) ); if (!promptInstall) { return false; } const prompts = await import('./index.BJDntFik.js').then(function (n) { return n.i; }); const { install } = await prompts.prompt({ type: "confirm", name: "install", message: c.reset(`Do you want to install ${c.green(dependency)}?`) }); if (install) { const packageName = version ? `${dependency}@${version}` : dependency; await (await import('./index.CqYx2Nsr.js')).installPackage(packageName, { dev: true }); process.stderr.write( c.yellow( ` Package ${packageName} installed, re-run the command to start. ` ) ); process.exit(); return true; } return false; } } async function loadCustomReporterModule(path, runner) { let customReporterModule; try { customReporterModule = await runner.executeId(path); } catch (customReporterModuleError) { throw new Error(`Failed to load custom Reporter from ${path}`, { cause: customReporterModuleError }); } if (customReporterModule.default === null || customReporterModule.default === void 0) { throw new Error( `Custom reporter loaded from ${path} was not the default export` ); } return customReporterModule.default; } function createReporters(reporterReferences, ctx) { const runner = ctx.runner; const promisedReporters = reporterReferences.map( async (referenceOrInstance) => { if (Array.isArray(referenceOrInstance)) { const [reporterName, reporterOptions] = referenceOrInstance; if (reporterName === "html") { await ctx.packageInstaller.ensureInstalled("@vitest/ui", runner.root, ctx.version); const CustomReporter = await loadCustomReporterModule( "@vitest/ui/reporter", runner ); return new CustomReporter(reporterOptions); } else if (reporterName in ReportersMap) { const BuiltinReporter = ReportersMap[reporterName]; return new BuiltinReporter(reporterOptions); } else { const CustomReporter = await loadCustomReporterModule( reporterName, runner ); return new CustomReporter(reporterOptions); } } return referenceOrInstance; } ); return Promise.all(promisedReporters); } function createBenchmarkReporters(reporterReferences, runner) { const promisedReporters = reporterReferences.map( async (referenceOrInstance) => { if (typeof referenceOrInstance === "string") { if (referenceOrInstance in BenchmarkReportsMap) { const BuiltinReporter = BenchmarkReportsMap[referenceOrInstance]; return new BuiltinReporter(); } else { const CustomReporter = await loadCustomReporterModule( referenceOrInstance, runner ); return new CustomReporter(); } } return referenceOrInstance; } ); return Promise.all(promisedReporters); } function isAggregateError(err) { if (typeof AggregateError !== "undefined" && err instanceof AggregateError) { return true; } return err instanceof Error && "errors" in err; } class StateManager { filesMap = /* @__PURE__ */ new Map(); pathsSet = /* @__PURE__ */ new Set(); idMap = /* @__PURE__ */ new Map(); taskFileMap = /* @__PURE__ */ new WeakMap(); errorsSet = /* @__PURE__ */ new Set(); processTimeoutCauses = /* @__PURE__ */ new Set(); reportedTasksMap = /* @__PURE__ */ new WeakMap(); catchError(err, type) { if (isAggregateError(err)) { return err.errors.forEach((error) => this.catchError(error, type)); } if (err === Object(err)) { err.type = type; } else { err = { type, message: err }; } const _err = err; if (_err && typeof _err === "object" && _err.code === "VITEST_PENDING") { const task = this.idMap.get(_err.taskId); if (task) { task.mode = "skip"; task.result ??= { state: "skip" }; task.result.state = "skip"; } return; } this.errorsSet.add(err); } clearErrors() { this.errorsSet.clear(); } getUnhandledErrors() { return Array.from(this.errorsSet.values()); } addProcessTimeoutCause(cause) { this.processTimeoutCauses.add(cause); } getProcessTimeoutCauses() { return Array.from(this.processTimeoutCauses.values()); } getPaths() { return Array.from(this.pathsSet); } /** * Return files that were running or collected. */ getFiles(keys) { if (keys) { return keys.map((key) => this.filesMap.get(key)).flat().filter((file) => file && !file.local); } return Array.from(this.filesMap.values()).flat().filter((file) => !file.local).sort((f1, f2) => { if (f1.meta?.typecheck && f2.meta?.typecheck) { return 0; } if (f1.meta?.typecheck) { return -1; } return 1; }); } getFilepaths() { return Array.from(this.filesMap.keys()); } getFailedFilepaths() { return this.getFiles().filter((i) => i.result?.state === "fail").map((i) => i.filepath); } collectPaths(paths = []) { paths.forEach((path) => { this.pathsSet.add(path); }); } collectFiles(project, files = []) { files.forEach((file) => { const existing = this.filesMap.get(file.filepath) || []; const otherFiles = existing.filter( (i) => i.projectName !== file.projectName || i.meta.typecheck !== file.meta.typecheck ); const currentFile = existing.find( (i) => i.projectName === file.projectName ); if (currentFile) { file.logs = currentFile.logs; } otherFiles.push(file); this.filesMap.set(file.filepath, otherFiles); this.updateId(file, project); }); } clearFiles(project, paths = []) { paths.forEach((path) => { const files = this.filesMap.get(path); const fileTask = createFileTask( path, project.config.root, project.config.name ); fileTask.local = true; TestModule.register(fileTask, project); this.idMap.set(fileTask.id, fileTask); if (!files) { this.filesMap.set(path, [fileTask]); return; } const filtered = files.filter( (file) => file.projectName !== project.config.name ); if (!filtered.length) { this.filesMap.set(path, [fileTask]); } else { this.filesMap.set(path, [...filtered, fileTask]); } }); } updateId(task, project) { if (this.idMap.get(task.id) === task) { return; } if (task.type === "suite" && "filepath" in task) { TestModule.register(task, project); } else if (task.type === "suite") { TestSuite.register(task, project); } else { TestCase.register(task, project); } this.idMap.set(task.id, task); if (task.type === "suite") { task.tasks.forEach((task2) => { this.updateId(task2, project); }); } } getReportedEntity(task) { return this.reportedTasksMap.get(task); } updateTasks(packs) { for (const [id, result, meta] of packs) { const task = this.idMap.get(id); if (task) { task.result = result; task.meta = meta; if (result?.state === "skip") { task.mode = "skip"; } } } } updateUserLog(log) { const task = log.taskId && this.idMap.get(log.taskId); if (task) { if (!task.logs) { task.logs = []; } task.logs.push(log); } } getCountOfFailedTests() { return Array.from(this.idMap.values()).filter( (t) => t.result?.state === "fail" ).length; } cancelFiles(files, project) { this.collectFiles( project, files.map( (filepath) => createFileTask(filepath, project.config.root, project.config.name) ) ); } } var tasks = {}; var utils$1 = {}; var array = {}; var hasRequiredArray; function requireArray () { if (hasRequiredArray) return array; hasRequiredArray = 1; Object.defineProperty(array, "__esModule", { value: true }); array.splitWhen = array.flatten = void 0; function flatten(items) { return items.reduce((collection, item) => [].concat(collection, item), []); } array.flatten = flatten; function splitWhen(items, predicate) { const result = [[]]; let groupIndex = 0; for (const item of items) { if (predicate(item)) { groupIndex++; result[groupIndex] = []; } else { result[groupIndex].push(item); } } return result; } array.splitWhen = splitWhen; return array; } var errno = {}; var hasRequiredErrno; function requireErrno () { if (hasRequiredErrno) return errno; hasRequiredErrno = 1; Object.defineProperty(errno, "__esModule", { value: true }); errno.isEnoentCodeError = void 0; function isEnoentCodeError(error) { return error.code === 'ENOENT'; } errno.isEnoentCodeError = isEnoentCodeError; return errno; } var fs$3 = {}; var hasRequiredFs$3; function requireFs$3 () { if (hasRequiredFs$3) return fs$3; hasRequiredFs$3 = 1; Object.defineProperty(fs$3, "__esModule", { value: true }); fs$3.createDirentFromStats = void 0; class DirentFromStats { constructor(name, stats) { this.name = name; this.isBlockDevice = stats.isBlockDevice.bind(stats); this.isCharacterDevice = stats.isCharacterDevice.bind(stats); this.isDirectory = stats.isDirectory.bind(stats); this.isFIFO = stats.isFIFO.bind(stats); this.isFile = stats.isFile.bind(stats); this.isSocket = stats.isSocket.bind(stats); this.isSymbolicLink = stats.isSymbolicLink.bind(stats); } } function createDirentFromStats(name, stats) { return new DirentFromStats(name, stats); } fs$3.createDirentFromStats = createDirentFromStats; return fs$3; } var path = {}; var hasRequiredPath; function requirePath () { if (hasRequiredPath) return path; hasRequiredPath = 1; Object.defineProperty(path, "__esModule", { value: true }); path.convertPosixPathToPattern = path.convertWindowsPathToPattern = path.convertPathToPattern = path.escapePosixPath = path.escapeWindowsPath = path.escape = path.removeLeadingDotSegment = path.makeAbsolute = path.unixify = void 0; const os = require$$0$4; const path$1 = require$$0$5; const IS_WINDOWS_PLATFORM = os.platform() === 'win32'; const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\ /** * All non-escaped special characters. * Posix: ()*?[]{|}, !+@ before (, ! at the beginning, \\ before non-special characters. * Windows: (){}[], !+@ before (, ! at the beginning. */ const POSIX_UNESCAPED_GLOB_SYMBOLS_RE = /(\\?)([()*?[\]{|}]|^!|[!+@](?=\()|\\(?![!()*+?@[\]{|}]))/g; const WINDOWS_UNESCAPED_GLOB_SYMBOLS_RE = /(\\?)([()[\]{}]|^!|[!+@](?=\())/g; /** * The device path (\\.\ or \\?\). * https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#dos-device-paths */ const DOS_DEVICE_PATH_RE = /^\\\\([.?])/; /** * All backslashes except those escaping special characters. * Windows: !()+@{} * https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions */ const WINDOWS_BACKSLASHES_RE = /\\(?![!()+@[\]{}])/g; /** * Designed to work only with simple paths: `dir\\file`. */ function unixify(filepath) { return filepath.replace(/\\/g, '/'); } path.unixify = unixify; function makeAbsolute(cwd, filepath) { return path$1.resolve(cwd, filepath); } path.makeAbsolute = makeAbsolute; function removeLeadingDotSegment(entry) { // We do not use `startsWith` because this is 10x slower than current implementation for some cases. // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with if (entry.charAt(0) === '.') { const secondCharactery = entry.charAt(1); if (secondCharactery === '/' || secondCharactery === '\\') { return entry.slice(LEADING_DOT_SEGMENT_CHARACTERS_COUNT); } } return entry; } path.removeLeadingDotSegment = removeLeadingDotSegment; path.escape = IS_WINDOWS_PLATFORM ? escapeWindowsPath : escapePosixPath; function escapeWindowsPath(pattern) { return pattern.replace(WINDOWS_UNESCAPED_GLOB_SYMBOLS_RE, '\\$2'); } path.escapeWindowsPath = escapeWindowsPath; function escapePosixPath(pattern) { return pattern.replace(POSIX_UNESCAPED_GLOB_SYMBOLS_RE, '\\$2'); } path.escapePosixPath = escapePosixPath; path.convertPathToPattern = IS_WINDOWS_PLATFORM ? convertWindowsPathToPattern : convertPosixPathToPattern; function convertWindowsPathToPattern(filepath) { return escapeWindowsPath(filepath) .replace(DOS_DEVICE_PATH_RE, '//$1') .replace(WINDOWS_BACKSLASHES_RE, '/'); } path.convertWindowsPathToPattern = convertWindowsPathToPattern; function convertPosixPathToPattern(filepath) { return escapePosixPath(filepath); } path.convertPosixPathToPattern = convertPosixPathToPattern; return path; } var pattern = {}; /*! * is-extglob * * Copyright (c) 2014-2016, Jon Schlinkert. * Licensed under the MIT License. */ var isExtglob; var hasRequiredIsExtglob; function requireIsExtglob () { if (hasRequiredIsExtglob) return isExtglob; hasRequiredIsExtglob = 1; isExtglob = function isExtglob(str) { if (typeof str !== 'string' || str === '') { return false; } var match; while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { if (match[2]) return true; str = str.slice(match.index + match[0].length); } return false; }; return isExtglob; } /*! * is-glob * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. */ var isGlob; var hasRequiredIsGlob; function requireIsGlob () { if (hasRequiredIsGlob) return isGlob; hasRequiredIsGlob = 1; var isExtglob = requireIsExtglob(); var chars = { '{': '}', '(': ')', '[': ']'}; var strictCheck = function(str) { if (str[0] === '!') { return true; } var index = 0; var pipeIndex = -2; var closeSquareIndex = -2; var closeCurlyIndex = -2; var closeParenIndex = -2; var backSlashIndex = -2; while (index < str.length) { if (str[index] === '*') { return true; } if (str[index + 1] === '?' && /[\].+)]/.test(str[index])) { return true; } if (closeSquareIndex !== -1 && str[index] === '[' && str[index + 1] !== ']') { if (closeSquareIndex < index) { closeSquareIndex = str.indexOf(']', index); } if (closeSquareIndex > index) { if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) { return true; } backSlashIndex = str.indexOf('\\', index); if (backSlashIndex === -1 || backSlashIndex > closeSquareIndex) { return true; } } } if (closeCurlyIndex !== -1 && str[index] === '{' && str[index + 1] !== '}') { closeCurlyIndex = str.indexOf('}', index); if (closeCurlyIndex > index) { backSlashIndex = str.indexOf('\\', index); if (backSlashIndex === -1 || backSlashIndex > closeCurlyIndex) { return true; } } } if (closeParenIndex !== -1 && str[index] === '(' && str[index + 1] === '?' && /[:!=]/.test(str[index + 2]) && str[index + 3] !== ')') { closeParenIndex = str.indexOf(')', index); if (closeParenIndex > index) { backSlashIndex = str.indexOf('\\', index); if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) { return true; } } } if (pipeIndex !== -1 && str[index] === '(' && str[index + 1] !== '|') { if (pipeIndex < index) { pipeIndex = str.indexOf('|', index); } if (pipeIndex !== -1 && str[pipeIndex + 1] !== ')') { closeParenIndex = str.indexOf(')', pipeIndex); if (closeParenIndex > pipeIndex) { backSlashIndex = str.indexOf('\\', pipeIndex); if (backSlashIndex === -1 || backSlashIndex > closeParenIndex) { return true; } } } } if (str[index] === '\\') { var open = str[index + 1]; index += 2; var close = chars[open]; if (close) { var n = str.indexOf(close, index); if (n !== -1) { index = n + 1; } } if (str[index] === '!') { return true; } } else { index++; } } return false; }; var relaxedCheck = function(str) { if (str[0] === '!') { return true; } var index = 0; while (index < str.length) { if (/[*?{}()[\]]/.test(str[index])) { return true; } if (str[index] === '\\') { var open = str[index + 1]; index += 2; var close = chars[open]; if (close) { var n = str.indexOf(close, index); if (n !== -1) { index = n + 1; } } if (str[index] === '!') { return true; } } else { index++; } } return false; }; isGlob = function isGlob(str, options) { if (typeof str !== 'string' || str === '') { return false; } if (isExtglob(str)) { return true; } var check = strictCheck; // optionally relax check if (options && options.strict === false) { check = relaxedCheck; } return check(str); }; return isGlob; } var globParent; var hasRequiredGlobParent; function requireGlobParent () { if (hasRequiredGlobParent) return globParent; hasRequiredGlobParent = 1; var isGlob = requireIsGlob(); var pathPosixDirname = require$$0$5.posix.dirname; var isWin32 = require$$0$4.platform() === 'win32'; var slash = '/'; var backslash = /\\/g; var enclosure = /[\{\[].*[\}\]]$/; var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g; /** * @param {string} str * @param {Object} opts * @param {boolean} [opts.flipBackslashes=true] * @returns {string} */ globParent = function globParent(str, opts) { var options = Object.assign({ flipBackslashes: true }, opts); // flip windows path separators if (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { str = str.replace(backslash, slash); } // special case for strings ending in enclosure containing path separator if (enclosure.test(str)) { str += slash; } // preserves full path in case of trailing path separator str += 'a'; // remove path parts that are globby do { str = pathPosixDirname(str); } while (isGlob(str) || globby.test(str)); // remove escape chars and return result return str.replace(escaped, '$1'); }; return globParent; } var hasRequiredPattern; function requirePattern () { if (hasRequiredPattern) return pattern; hasRequiredPattern = 1; Object.defineProperty(pattern, "__esModule", { value: true }); pattern.removeDuplicateSlashes = pattern.matchAny = pattern.convertPatternsToRe = pattern.makeRe = pattern.getPatternParts = pattern.expandBraceExpansion = pattern.expandPatternsWithBraceExpansion = pattern.isAffectDepthOfReadingPattern = pattern.endsWithSlashGlobStar = pattern.hasGlobStar = pattern.getBaseDirectory = pattern.isPatternRelatedToParentDirectory = pattern.getPatternsOutsideCurrentDirectory = pattern.getPatternsInsideCurrentDirectory = pattern.getPositivePatterns = pattern.getNegativePatterns = pattern.isPositivePattern = pattern.isNegativePattern = pattern.convertToNegativePattern = pattern.convertToPositivePattern = pattern.isDynamicPattern = pattern.isStaticPattern = void 0; const path = require$$0$5; const globParent = requireGlobParent(); const micromatch = requireMicromatch(); const GLOBSTAR = '**'; const ESCAPE_SYMBOL = '\\'; const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; const REGEX_CHARACTER_CLASS_SYMBOLS_RE = /\[[^[]*]/; const REGEX_GROUP_SYMBOLS_RE = /(?:^|[^!*+?@])\([^(]*\|[^|]*\)/; const GLOB_EXTENSION_SYMBOLS_RE = /[!*+?@]\([^(]*\)/; const BRACE_EXPANSION_SEPARATORS_RE = /,|\.\./; /** * Matches a sequence of two or more consecutive slashes, excluding the first two slashes at the beginning of the string. * The latter is due to the presence of the device path at the beginning of the UNC path. */ const DOUBLE_SLASH_RE = /(?!^)\/{2,}/g; function isStaticPattern(pattern, options = {}) { return !isDynamicPattern(pattern, options); } pattern.isStaticPattern = isStaticPattern; function isDynamicPattern(pattern, options = {}) { /** * A special case with an empty string is necessary for matching patterns that start with a forward slash. * An empty string cannot be a dynamic pattern. * For example, the pattern `/lib/*` will be spread into parts: '', 'lib', '*'. */ if (pattern === '') { return false; } /** * When the `caseSensitiveMatch` option is disabled, all patterns must be marked as dynamic, because we cannot check * filepath directly (without read directory). */ if (options.caseSensitiveMatch === false || pattern.includes(ESCAPE_SYMBOL)) { return true; } if (COMMON_GLOB_SYMBOLS_RE.test(pattern) || REGEX_CHARACTER_CLASS_SYMBOLS_RE.test(pattern) || REGEX_GROUP_SYMBOLS_RE.test(pattern)) { return true; } if (options.extglob !== false && GLOB_EXTENSION_SYMBOLS_RE.test(pattern)) { return true; } if (options.braceExpansion !== false && hasBraceExpansion(pattern)) { return true; } return false; } pattern.isDynamicPattern = isDynamicPattern; function hasBraceExpansion(pattern) { const openingBraceIndex = pattern.indexOf('{'); if (openingBraceIndex === -1) { return false; } const closingBraceIndex = pattern.indexOf('}', openingBraceIndex + 1); if (closingBraceIndex === -1) { return false; } const braceContent = pattern.slice(openingBraceIndex, closingBraceIndex); return BRACE_EXPANSION_SEPARATORS_RE.test(braceContent); } function convertToPositivePattern(pattern) { return isNegativePattern(pattern) ? pattern.slice(1) : pattern; } pattern.convertToPositivePattern = convertToPositivePattern; function convertToNegativePattern(pattern) { return '!' + pattern; } pattern.convertToNegativePattern = convertToNegativePattern; function isNegativePattern(pattern) { return pattern.startsWith('!') && pattern[1] !== '('; } pattern.isNegativePattern = isNegativePattern; function isPositivePattern(pattern) { return !isNegativePattern(pattern); } pattern.isPositivePattern = isPositivePattern; function getNegativePatterns(patterns) { return patterns.filter(isNegativePattern); } pattern.getNegativePatterns = getNegativePatterns; function getPositivePatterns(patterns) { return patterns.filter(isPositivePattern); } pattern.getPositivePatterns = getPositivePatterns; /** * Returns patterns that can be applied inside the current directory. * * @example * // ['./*', '*', 'a/*'] * getPatternsInsideCurrentDirectory(['./*', '*', 'a/*', '../*', './../*']) */ function getPatternsInsideCurrentDirectory(patterns) { return patterns.filter((pattern) => !isPatternRelatedToParentDirectory(pattern)); } pattern.getPatternsInsideCurrentDirectory = getPatternsInsideCurrentDirectory; /** * Returns patterns to be expanded relative to (outside) the current directory. * * @example * // ['../*', './../*'] * getPatternsInsideCurrentDirectory(['./*', '*', 'a/*', '../*', './../*']) */ function getPatternsOutsideCurrentDirectory(patterns) { return patterns.filter(isPatternRelatedToParentDirectory); } pattern.getPatternsOutsideCurrentDirectory = getPatternsOutsideCurrentDirectory; function isPatternRelatedToParentDirectory(pattern) { return pattern.startsWith('..') || pattern.startsWith('./..'); } pattern.isPatternRelatedToParentDirectory = isPatternRelatedToParentDirectory; function getBaseDirectory(pattern) { return globParent(pattern, { flipBackslashes: false }); } pattern.getBaseDirectory = getBaseDirectory; function hasGlobStar(pattern) { return pattern.includes(GLOBSTAR); } pattern.hasGlobStar = hasGlobStar; function endsWithSlashGlobStar(pattern) { return pattern.endsWith('/' + GLOBSTAR); } pattern.endsWithSlashGlobStar = endsWithSlashGlobStar; function isAffectDepthOfReadingPattern(pattern) { const basename = path.basename(pattern); return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); } pattern.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; function expandPatternsWithBraceExpansion(patterns) { return patterns.reduce((collection, pattern) => { return collection.concat(expandBraceExpansion(pattern)); }, []); } pattern.expandPatternsWithBraceExpansion = expandPatternsWithBraceExpansion; function expandBraceExpansion(pattern) { const patterns = micromatch.braces(pattern, { expand: true, nodupes: true, keepEscaping: true }); /** * Sort the patterns by length so that the same depth patterns are processed side by side. * `a/{b,}/{c,}/*` – `['a///*', 'a/b//*', 'a//c/*', 'a/b/c/*']` */ patterns.sort((a, b) => a.length - b.length); /** * Micromatch can return an empty string in the case of patterns like `{a,}`. */ return patterns.filter((pattern) => pattern !== ''); } pattern.expandBraceExpansion = expandBraceExpansion; function getPatternParts(pattern, options) { let { parts } = micromatch.scan(pattern, Object.assign(Object.assign({}, options), { parts: true })); /** * The scan method returns an empty array in some cases. * See micromatch/picomatch#58 for more details. */ if (parts.length === 0) { parts = [pattern]; } /** * The scan method does not return an empty part for the pattern with a forward slash. * This is another part of micromatch/picomatch#58. */ if (parts[0].startsWith('/')) { parts[0] = parts[0].slice(1); parts.unshift(''); } return parts; } pattern.getPatternParts = getPatternParts; function makeRe(pattern, options) { return micromatch.makeRe(pattern, options); } pattern.makeRe = makeRe; function convertPatternsToRe(patterns, options) { return patterns.map((pattern) => makeRe(pattern, options)); } pattern.convertPatternsToRe = convertPatternsToRe; function matchAny(entry, patternsRe) { return patternsRe.some((patternRe) => patternRe.test(entry)); } pattern.matchAny = matchAny; /** * This package only works with forward slashes as a path separator. * Because of this, we cannot use the standard `path.normalize` method, because on Windows platform it will use of backslashes. */ function removeDuplicateSlashes(pattern) { return pattern.replace(DOUBLE_SLASH_RE, '/'); } pattern.removeDuplicateSlashes = removeDuplicateSlashes; return pattern; } var stream$3 = {}; var merge2_1; var hasRequiredMerge2; function requireMerge2 () { if (hasRequiredMerge2) return merge2_1; hasRequiredMerge2 = 1; /* * merge2 * https://github.com/teambition/merge2 * * Copyright (c) 2014-2020 Teambition * Licensed under the MIT license. */ const Stream = require$$0$2; const PassThrough = Stream.PassThrough; const slice = Array.prototype.slice; merge2_1 = merge2; function merge2 () { const streamsQueue = []; const args = slice.call(arguments); let merging = false; let options = args[args.length - 1]; if (options && !Array.isArray(options) && options.pipe == null) { args.pop(); } else { options = {}; } const doEnd = options.end !== false; const doPipeError = options.pipeError === true; if (options.objectMode == null) { options.objectMode = true; } if (options.highWaterMark == null) { options.highWaterMark = 64 * 1024; } const mergedStream = PassThrough(options); function addStream () { for (let i = 0, len = arguments.length; i < len; i++) { streamsQueue.push(pauseStreams(arguments[i], options)); } mergeStream(); return this } function mergeStream () { if (merging) { return } merging = true; let streams = streamsQueue.shift(); if (!streams) { process.nextTick(endStream); return } if (!Array.isArray(streams)) { streams = [streams]; } let pipesCount = streams.length + 1; function next () { if (--pipesCount > 0) { return } merging = false; mergeStream(); } function pipe (stream) { function onend () { stream.removeListener('merge2UnpipeEnd', onend); stream.removeListener('end', onend); if (doPipeError) { stream.removeListener('error', onerror); } next(); } function onerror (err) { mergedStream.emit('error', err); } // skip ended stream if (stream._readableState.endEmitted) { return next() } stream.on('merge2UnpipeEnd', onend); stream.on('end', onend); if (doPipeError) { stream.on('error', onerror); } stream.pipe(mergedStream, { end: false }); // compatible for old stream stream.resume(); } for (let i = 0; i < streams.length; i++) { pipe(streams[i]); } next(); } function endStream () { merging = false; // emit 'queueDrain' when all streams merged. mergedStream.emit('queueDrain'); if (doEnd) { mergedStream.end(); } } mergedStream.setMaxListeners(0); mergedStream.add = addStream; mergedStream.on('unpipe', function (stream) { stream.emit('merge2UnpipeEnd'); }); if (args.length) { addStream.apply(null, args); } return mergedStream } // check and pause streams for pipe. function pauseStreams (streams, options) { if (!Array.isArray(streams)) { // Backwards-compat with old-style streams if (!streams._readableState && streams.pipe) { streams = streams.pipe(PassThrough(options)); } if (!streams._readableState || !streams.pause || !streams.pipe) { throw new Error('Only readable stream can be merged.') } streams.pause(); } else { for (let i = 0, len = streams.length; i < len; i++) { streams[i] = pauseStreams(streams[i], options); } } return streams } return merge2_1; } var hasRequiredStream$3; function requireStream$3 () { if (hasRequiredStream$3) return stream$3; hasRequiredStream$3 = 1; Object.defineProperty(stream$3, "__esModule", { value: true }); stream$3.merge = void 0; const merge2 = requireMerge2(); function merge(streams) { const mergedStream = merge2(streams); streams.forEach((stream) => { stream.once('error', (error) => mergedStream.emit('error', error)); }); mergedStream.once('close', () => propagateCloseEventToSources(streams)); mergedStream.once('end', () => propagateCloseEventToSources(streams)); return mergedStream; } stream$3.merge = merge; function propagateCloseEventToSources(streams) { streams.forEach((stream) => stream.emit('close')); } return stream$3; } var string = {}; var hasRequiredString; function requireString () { if (hasRequiredString) return string; hasRequiredString = 1; Object.defineProperty(string, "__esModule", { value: true }); string.isEmpty = string.isString = void 0; function isString(input) { return typeof input === 'string'; } string.isString = isString; function isEmpty(input) { return input === ''; } string.isEmpty = isEmpty; return string; } var hasRequiredUtils$1; function requireUtils$1 () { if (hasRequiredUtils$1) return utils$1; hasRequiredUtils$1 = 1; Object.defineProperty(utils$1, "__esModule", { value: true }); utils$1.string = utils$1.stream = utils$1.pattern = utils$1.path = utils$1.fs = utils$1.errno = utils$1.array = void 0; const array = requireArray(); utils$1.array = array; const errno = requireErrno(); utils$1.errno = errno; const fs = requireFs$3(); utils$1.fs = fs; const path = requirePath(); utils$1.path = path; const pattern = requirePattern(); utils$1.pattern = pattern; const stream = requireStream$3(); utils$1.stream = stream; const string = requireString(); utils$1.string = string; return utils$1; } var hasRequiredTasks; function requireTasks () { if (hasRequiredTasks) return tasks; hasRequiredTasks = 1; Object.defineProperty(tasks, "__esModule", { value: true }); tasks.convertPatternGroupToTask = tasks.convertPatternGroupsToTasks = tasks.groupPatternsByBaseDirectory = tasks.getNegativePatternsAsPositive = tasks.getPositivePatterns = tasks.convertPatternsToTasks = tasks.generate = void 0; const utils = requireUtils$1(); function generate(input, settings) { const patterns = processPatterns(input, settings); const ignore = processPatterns(settings.ignore, settings); const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, ignore); const staticPatterns = positivePatterns.filter((pattern) => utils.pattern.isStaticPattern(pattern, settings)); const dynamicPatterns = positivePatterns.filter((pattern) => utils.pattern.isDynamicPattern(pattern, settings)); const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); return staticTasks.concat(dynamicTasks); } tasks.generate = generate; function processPatterns(input, settings) { let patterns = input; /** * The original pattern like `{,*,**,a/*}` can lead to problems checking the depth when matching entry * and some problems with the micromatch package (see fast-glob issues: #365, #394). * * To solve this problem, we expand all patterns containing brace expansion. This can lead to a slight slowdown * in matching in the case of a large set of patterns after expansion. */ if (settings.braceExpansion) { patterns = utils.pattern.expandPatternsWithBraceExpansion(patterns); } /** * If the `baseNameMatch` option is enabled, we must add globstar to patterns, so that they can be used * at any nesting level. * * We do this here, because otherwise we have to complicate the filtering logic. For example, we need to change * the pattern in the filter before creating a regular expression. There is no need to change the patterns * in the application. Only on the input. */ if (settings.baseNameMatch) { patterns = patterns.map((pattern) => pattern.includes('/') ? pattern : `**/${pattern}`); } /** * This method also removes duplicate slashes that may have been in the pattern or formed as a result of expansion. */ return patterns.map((pattern) => utils.pattern.removeDuplicateSlashes(pattern)); } /** * Returns tasks grouped by basic pattern directories. * * Patterns that can be found inside (`./`) and outside (`../`) the current directory are handled separately. * This is necessary because directory traversal starts at the base directory and goes deeper. */ function convertPatternsToTasks(positive, negative, dynamic) { const tasks = []; const patternsOutsideCurrentDirectory = utils.pattern.getPatternsOutsideCurrentDirectory(positive); const patternsInsideCurrentDirectory = utils.pattern.getPatternsInsideCurrentDirectory(positive); const outsideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsOutsideCurrentDirectory); const insideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsInsideCurrentDirectory); tasks.push(...convertPatternGroupsToTasks(outsideCurrentDirectoryGroup, negative, dynamic)); /* * For the sake of reducing future accesses to the file system, we merge all tasks within the current directory * into a global task, if at least one pattern refers to the root (`.`). In this case, the global task covers the rest. */ if ('.' in insideCurrentDirectoryGroup) { tasks.push(convertPatternGroupToTask('.', patternsInsideCurrentDirectory, negative, dynamic)); } else { tasks.push(...convertPatternGroupsToTasks(insideCurrentDirectoryGroup, negative, dynamic)); } return tasks; } tasks.convertPatternsToTasks = convertPatternsToTasks; function getPositivePatterns(patterns) { return utils.pattern.getPositivePatterns(patterns); } tasks.getPositivePatterns = getPositivePatterns; function getNegativePatternsAsPositive(patterns, ignore) { const negative = utils.pattern.getNegativePatterns(patterns).concat(ignore); const positive = negative.map(utils.pattern.convertToPositivePattern); return positive; } tasks.getNegativePatternsAsPositive = getNegativePatternsAsPositive; function groupPatternsByBaseDirectory(patterns) { const group = {}; return patterns.reduce((collection, pattern) => { const base = utils.pattern.getBaseDirectory(pattern); if (base in collection) { collection[base].push(pattern); } else { collection[base] = [pattern]; } return collection; }, group); } tasks.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; function convertPatternGroupsToTasks(positive, negative, dynamic) { return Object.keys(positive).map((base) => { return convertPatternGroupToTask(base, positive[base], negative, dynamic); }); } tasks.convertPatternGroupsToTasks = convertPatternGroupsToTasks; function convertPatternGroupToTask(base, positive, negative, dynamic) { return { dynamic, positive, negative, base, patterns: [].concat(positive, negative.map(utils.pattern.convertToNegativePattern)) }; } tasks.convertPatternGroupToTask = convertPatternGroupToTask; return tasks; } var async$5 = {}; var async$4 = {}; var out$3 = {}; var async$3 = {}; var async$2 = {}; var out$2 = {}; var async$1 = {}; var out$1 = {}; var async = {}; var hasRequiredAsync$5; function requireAsync$5 () { if (hasRequiredAsync$5) return async; hasRequiredAsync$5 = 1; Object.defineProperty(async, "__esModule", { value: true }); async.read = void 0; function read(path, settings, callback) { settings.fs.lstat(path, (lstatError, lstat) => { if (lstatError !== null) { callFailureCallback(callback, lstatError); return; } if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { callSuccessCallback(callback, lstat); return; } settings.fs.stat(path, (statError, stat) => { if (statError !== null) { if (settings.throwErrorOnBrokenSymbolicLink) { callFailureCallback(callback, statError); return; } callSuccessCallback(callback, lstat); return; } if (settings.markSymbolicLink) { stat.isSymbolicLink = () => true; } callSuccessCallback(callback, stat); }); }); } async.read = read; function callFailureCallback(callback, error) { callback(error); } function callSuccessCallback(callback, result) { callback(null, result); } return async; } var sync$5 = {}; var hasRequiredSync$5; function requireSync$5 () { if (hasRequiredSync$5) return sync$5; hasRequiredSync$5 = 1; Object.defineProperty(sync$5, "__esModule", { value: true }); sync$5.read = void 0; function read(path, settings) { const lstat = settings.fs.lstatSync(path); if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { return lstat; } try { const stat = settings.fs.statSync(path); if (settings.markSymbolicLink) { stat.isSymbolicLink = () => true; } return stat; } catch (error) { if (!settings.throwErrorOnBrokenSymbolicLink) { return lstat; } throw error; } } sync$5.read = read; return sync$5; } var settings$3 = {}; var fs$2 = {}; var hasRequiredFs$2; function requireFs$2 () { if (hasRequiredFs$2) return fs$2; hasRequiredFs$2 = 1; (function (exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0; const fs = require$$0$6; exports.FILE_SYSTEM_ADAPTER = { lstat: fs.lstat, stat: fs.stat, lstatSync: fs.lstatSync, statSync: fs.statSync }; function createFileSystemAdapter(fsMethods) { if (fsMethods === undefined) { return exports.FILE_SYSTEM_ADAPTER; } return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); } exports.createFileSystemAdapter = createFileSystemAdapter; } (fs$2)); return fs$2; } var hasRequiredSettings$3; function requireSettings$3 () { if (hasRequiredSettings$3) return settings$3; hasRequiredSettings$3 = 1; Object.defineProperty(settings$3, "__esModule", { value: true }); const fs = requireFs$2(); class Settings { constructor(_options = {}) { this._options = _options; this.followSymbolicLink = this._getValue(this._options.followSymbolicLink, true); this.fs = fs.createFileSystemAdapter(this._options.fs); this.markSymbolicLink = this._getValue(this._options.markSymbolicLink, false); this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); } _getValue(option, value) { return option !== null && option !== void 0 ? option : value; } } settings$3.default = Settings; return settings$3; } var hasRequiredOut$3; function requireOut$3 () { if (hasRequiredOut$3) return out$1; hasRequiredOut$3 = 1; Object.defineProperty(out$1, "__esModule", { value: true }); out$1.statSync = out$1.stat = out$1.Settings = void 0; const async = requireAsync$5(); const sync = requireSync$5(); const settings_1 = requireSettings$3(); out$1.Settings = settings_1.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { async.read(path, getSettings(), optionsOrSettingsOrCallback); return; } async.read(path, getSettings(optionsOrSettingsOrCallback), callback); } out$1.stat = stat; function statSync(path, optionsOrSettings) { const settings = getSettings(optionsOrSettings); return sync.read(path, settings); } out$1.statSync = statSync; function getSettings(settingsOrOptions = {}) { if (settingsOrOptions instanceof settings_1.default) { return settingsOrOptions; } return new settings_1.default(settingsOrOptions); } return out$1; } /*! queue-microtask. MIT License. Feross Aboukhadijeh */ var queueMicrotask_1; var hasRequiredQueueMicrotask; function requireQueueMicrotask () { if (hasRequiredQueueMicrotask) return queueMicrotask_1; hasRequiredQueueMicrotask = 1; let promise; queueMicrotask_1 = typeof queueMicrotask === 'function' ? queueMicrotask.bind(typeof window !== 'undefined' ? window : commonjsGlobal) // reuse resolved promise, and allocate it lazily : cb => (promise || (promise = Promise.resolve())) .then(cb) .catch(err => setTimeout(() => { throw err }, 0)); return queueMicrotask_1; } /*! run-parallel. MIT License. Feross Aboukhadijeh */ var runParallel_1; var hasRequiredRunParallel; function requireRunParallel () { if (hasRequiredRunParallel) return runParallel_1; hasRequiredRunParallel = 1; runParallel_1 = runParallel; const queueMicrotask = requireQueueMicrotask(); function runParallel (tasks, cb) { let results, pending, keys; let isSync = true; if (Array.isArray(tasks)) { results = []; pending = tasks.length; } else { keys = Object.keys(tasks); results = {}; pending = keys.length; } function done (err) { function end () { if (cb) cb(err, results); cb = null; } if (isSync) queueMicrotask(end); else end(); } function each (i, err, result) { results[i] = result; if (--pending === 0 || err) { done(err); } } if (!pending) { // empty done(null); } else if (keys) { // object keys.forEach(function (key) { tasks[key](function (err, result) { each(key, err, result); }); }); } else { // array tasks.forEach(function (task, i) { task(function (err, result) { each(i, err, result); }); }); } isSync = false; } return runParallel_1; } var constants = {}; var hasRequiredConstants; function requireConstants () { if (hasRequiredConstants) return constants; hasRequiredConstants = 1; Object.defineProperty(constants, "__esModule", { value: true }); constants.IS_SUPPORT_READDIR_WITH_FILE_TYPES = void 0; const NODE_PROCESS_VERSION_PARTS = process.versions.node.split('.'); if (NODE_PROCESS_VERSION_PARTS[0] === undefined || NODE_PROCESS_VERSION_PARTS[1] === undefined) { throw new Error(`Unexpected behavior. The 'process.versions.node' variable has invalid value: ${process.versions.node}`); } const MAJOR_VERSION = Number.parseInt(NODE_PROCESS_VERSION_PARTS[0], 10); const MINOR_VERSION = Number.parseInt(NODE_PROCESS_VERSION_PARTS[1], 10); const SUPPORTED_MAJOR_VERSION = 10; const SUPPORTED_MINOR_VERSION = 10; const IS_MATCHED_BY_MAJOR = MAJOR_VERSION > SUPPORTED_MAJOR_VERSION; const IS_MATCHED_BY_MAJOR_AND_MINOR = MAJOR_VERSION === SUPPORTED_MAJOR_VERSION && MINOR_VERSION >= SUPPORTED_MINOR_VERSION; /** * IS `true` for Node.js 10.10 and greater. */ constants.IS_SUPPORT_READDIR_WITH_FILE_TYPES = IS_MATCHED_BY_MAJOR || IS_MATCHED_BY_MAJOR_AND_MINOR; return constants; } var utils = {}; var fs$1 = {}; var hasRequiredFs$1; function requireFs$1 () { if (hasRequiredFs$1) return fs$1; hasRequiredFs$1 = 1; Object.defineProperty(fs$1, "__esModule", { value: true }); fs$1.createDirentFromStats = void 0; class DirentFromStats { constructor(name, stats) { this.name = name; this.isBlockDevice = stats.isBlockDevice.bind(stats); this.isCharacterDevice = stats.isCharacterDevice.bind(stats); this.isDirectory = stats.isDirectory.bind(stats); this.isFIFO = stats.isFIFO.bind(stats); this.isFile = stats.isFile.bind(stats); this.isSocket = stats.isSocket.bind(stats); this.isSymbolicLink = stats.isSymbolicLink.bind(stats); } } function createDirentFromStats(name, stats) { return new DirentFromStats(name, stats); } fs$1.createDirentFromStats = createDirentFromStats; return fs$1; } var hasRequiredUtils; function requireUtils () { if (hasRequiredUtils) return utils; hasRequiredUtils = 1; Object.defineProperty(utils, "__esModule", { value: true }); utils.fs = void 0; const fs = requireFs$1(); utils.fs = fs; return utils; } var common$1 = {}; var hasRequiredCommon$1; function requireCommon$1 () { if (hasRequiredCommon$1) return common$1; hasRequiredCommon$1 = 1; Object.defineProperty(common$1, "__esModule", { value: true }); common$1.joinPathSegments = void 0; function joinPathSegments(a, b, separator) { /** * The correct handling of cases when the first segment is a root (`/`, `C:/`) or UNC path (`//?/C:/`). */ if (a.endsWith(separator)) { return a + b; } return a + separator + b; } common$1.joinPathSegments = joinPathSegments; return common$1; } var hasRequiredAsync$4; function requireAsync$4 () { if (hasRequiredAsync$4) return async$1; hasRequiredAsync$4 = 1; Object.defineProperty(async$1, "__esModule", { value: true }); async$1.readdir = async$1.readdirWithFileTypes = async$1.read = void 0; const fsStat = requireOut$3(); const rpl = requireRunParallel(); const constants_1 = requireConstants(); const utils = requireUtils(); const common = requireCommon$1(); function read(directory, settings, callback) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { readdirWithFileTypes(directory, settings, callback); return; } readdir(directory, settings, callback); } async$1.read = read; function readdirWithFileTypes(directory, settings, callback) { settings.fs.readdir(directory, { withFileTypes: true }, (readdirError, dirents) => { if (readdirError !== null) { callFailureCallback(callback, readdirError); return; } const entries = dirents.map((dirent) => ({ dirent, name: dirent.name, path: common.joinPathSegments(directory, dirent.name, settings.pathSegmentSeparator) })); if (!settings.followSymbolicLinks) { callSuccessCallback(callback, entries); return; } const tasks = entries.map((entry) => makeRplTaskEntry(entry, settings)); rpl(tasks, (rplError, rplEntries) => { if (rplError !== null) { callFailureCallback(callback, rplError); return; } callSuccessCallback(callback, rplEntries); }); }); } async$1.readdirWithFileTypes = readdirWithFileTypes; function makeRplTaskEntry(entry, settings) { return (done) => { if (!entry.dirent.isSymbolicLink()) { done(null, entry); return; } settings.fs.stat(entry.path, (statError, stats) => { if (statError !== null) { if (settings.throwErrorOnBrokenSymbolicLink) { done(statError); return; } done(null, entry); return; } entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); done(null, entry); }); }; } function readdir(directory, settings, callback) { settings.fs.readdir(directory, (readdirError, names) => { if (readdirError !== null) { callFailureCallback(callback, readdirError); return; } const tasks = names.map((name) => { const path = common.joinPathSegments(directory, name, settings.pathSegmentSeparator); return (done) => { fsStat.stat(path, settings.fsStatSettings, (error, stats) => { if (error !== null) { done(error); return; } const entry = { name, path, dirent: utils.fs.createDirentFromStats(name, stats) }; if (settings.stats) { entry.stats = stats; } done(null, entry); }); }; }); rpl(tasks, (rplError, entries) => { if (rplError !== null) { callFailureCallback(callback, rplError); return; } callSuccessCallback(callback, entries); }); }); } async$1.readdir = readdir; function callFailureCallback(callback, error) { callback(error); } function callSuccessCallback(callback, result) { callback(null, result); } return async$1; } var sync$4 = {}; var hasRequiredSync$4; function requireSync$4 () { if (hasRequiredSync$4) return sync$4; hasRequiredSync$4 = 1; Object.defineProperty(sync$4, "__esModule", { value: true }); sync$4.readdir = sync$4.readdirWithFileTypes = sync$4.read = void 0; const fsStat = requireOut$3(); const constants_1 = requireConstants(); const utils = requireUtils(); const common = requireCommon$1(); function read(directory, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(directory, settings); } return readdir(directory, settings); } sync$4.read = read; function readdirWithFileTypes(directory, settings) { const dirents = settings.fs.readdirSync(directory, { withFileTypes: true }); return dirents.map((dirent) => { const entry = { dirent, name: dirent.name, path: common.joinPathSegments(directory, dirent.name, settings.pathSegmentSeparator) }; if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { try { const stats = settings.fs.statSync(entry.path); entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); } catch (error) { if (settings.throwErrorOnBrokenSymbolicLink) { throw error; } } } return entry; }); } sync$4.readdirWithFileTypes = readdirWithFileTypes; function readdir(directory, settings) { const names = settings.fs.readdirSync(directory); return names.map((name) => { const entryPath = common.joinPathSegments(directory, name, settings.pathSegmentSeparator); const stats = fsStat.statSync(entryPath, settings.fsStatSettings); const entry = { name, path: entryPath, dirent: utils.fs.createDirentFromStats(name, stats) }; if (settings.stats) { entry.stats = stats; } return entry; }); } sync$4.readdir = readdir; return sync$4; } var settings$2 = {}; var fs = {}; var hasRequiredFs; function requireFs () { if (hasRequiredFs) return fs; hasRequiredFs = 1; (function (exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0; const fs = require$$0$6; exports.FILE_SYSTEM_ADAPTER = { lstat: fs.lstat, stat: fs.stat, lstatSync: fs.lstatSync, statSync: fs.statSync, readdir: fs.readdir, readdirSync: fs.readdirSync }; function createFileSystemAdapter(fsMethods) { if (fsMethods === undefined) { return exports.FILE_SYSTEM_ADAPTER; } return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); } exports.createFileSystemAdapter = createFileSystemAdapter; } (fs)); return fs; } var hasRequiredSettings$2; function requireSettings$2 () { if (hasRequiredSettings$2) return settings$2; hasRequiredSettings$2 = 1; Object.defineProperty(settings$2, "__esModule", { value: true }); const path = require$$0$5; const fsStat = requireOut$3(); const fs = requireFs(); class Settings { constructor(_options = {}) { this._options = _options; this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, false); this.fs = fs.createFileSystemAdapter(this._options.fs); this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); this.stats = this._getValue(this._options.stats, false); this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); this.fsStatSettings = new fsStat.Settings({ followSymbolicLink: this.followSymbolicLinks, fs: this.fs, throwErrorOnBrokenSymbolicLink: this.throwErrorOnBrokenSymbolicLink }); } _getValue(option, value) { return option !== null && option !== void 0 ? option : value; } } settings$2.default = Settings; return settings$2; } var hasRequiredOut$2; function requireOut$2 () { if (hasRequiredOut$2) return out$2; hasRequiredOut$2 = 1; Object.defineProperty(out$2, "__esModule", { value: true }); out$2.Settings = out$2.scandirSync = out$2.scandir = void 0; const async = requireAsync$4(); const sync = requireSync$4(); const settings_1 = requireSettings$2(); out$2.Settings = settings_1.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { async.read(path, getSettings(), optionsOrSettingsOrCallback); return; } async.read(path, getSettings(optionsOrSettingsOrCallback), callback); } out$2.scandir = scandir; function scandirSync(path, optionsOrSettings) { const settings = getSettings(optionsOrSettings); return sync.read(path, settings); } out$2.scandirSync = scandirSync; function getSettings(settingsOrOptions = {}) { if (settingsOrOptions instanceof settings_1.default) { return settingsOrOptions; } return new settings_1.default(settingsOrOptions); } return out$2; } var queue = {exports: {}}; var reusify_1; var hasRequiredReusify; function requireReusify () { if (hasRequiredReusify) return reusify_1; hasRequiredReusify = 1; function reusify (Constructor) { var head = new Constructor(); var tail = head; function get () { var current = head; if (current.next) { head = current.next; } else { head = new Constructor(); tail = head; } current.next = null; return current } function release (obj) { tail.next = obj; tail = obj; } return { get: get, release: release } } reusify_1 = reusify; return reusify_1; } var hasRequiredQueue; function requireQueue () { if (hasRequiredQueue) return queue.exports; hasRequiredQueue = 1; /* eslint-disable no-var */ var reusify = requireReusify(); function fastqueue (context, worker, _concurrency) { if (typeof context === 'function') { _concurrency = worker; worker = context; context = null; } if (!(_concurrency >= 1)) { throw new Error('fastqueue concurrency must be equal to or greater than 1') } var cache = reusify(Task); var queueHead = null; var queueTail = null; var _running = 0; var errorHandler = null; var self = { push: push, drain: noop, saturated: noop, pause: pause, paused: false, get concurrency () { return _concurrency }, set concurrency (value) { if (!(value >= 1)) { throw new Error('fastqueue concurrency must be equal to or greater than 1') } _concurrency = value; if (self.paused) return for (; queueHead && _running < _concurrency;) { _running++; release(); } }, running: running, resume: resume, idle: idle, length: length, getQueue: getQueue, unshift: unshift, empty: noop, kill: kill, killAndDrain: killAndDrain, error: error }; return self function running () { return _running } function pause () { self.paused = true; } function length () { var current = queueHead; var counter = 0; while (current) { current = current.next; counter++; } return counter } function getQueue () { var current = queueHead; var tasks = []; while (current) { tasks.push(current.value); current = current.next; } return tasks } function resume () { if (!self.paused) return self.paused = false; if (queueHead === null) { _running++; release(); return } for (; queueHead && _running < _concurrency;) { _running++; release(); } } function idle () { return _running === 0 && self.length() === 0 } function push (value, done) { var current = cache.get(); current.context = context; current.release = release; current.value = value; current.callback = done || noop; current.errorHandler = errorHandler; if (_running >= _concurrency || self.paused) { if (queueTail) { queueTail.next = current; queueTail = current; } else { queueHead = current; queueTail = current; self.saturated(); } } else { _running++; worker.call(context, current.value, current.worked); } } function unshift (value, done) { var current = cache.get(); current.context = context; current.release = release; current.value = value; current.callback = done || noop; current.errorHandler = errorHandler; if (_running >= _concurrency || self.paused) { if (queueHead) { current.next = queueHead; queueHead = current; } else { queueHead = current; queueTail = current; self.saturated(); } } else { _running++; worker.call(context, current.value, current.worked); } } function release (holder) { if (holder) { cache.release(holder); } var next = queueHead; if (next && _running <= _concurrency) { if (!self.paused) { if (queueTail === queueHead) { queueTail = null; } queueHead = next.next; next.next = null; worker.call(context, next.value, next.worked); if (queueTail === null) { self.empty(); } } else { _running--; } } else if (--_running === 0) { self.drain(); } } function kill () { queueHead = null; queueTail = null; self.drain = noop; } function killAndDrain () { queueHead = null; queueTail = null; self.drain(); self.drain = noop; } function error (handler) { errorHandler = handler; } } function noop () {} function Task () { this.value = null; this.callback = noop; this.next = null; this.release = noop; this.context = null; this.errorHandler = null; var self = this; this.worked = function worked (err, result) { var callback = self.callback; var errorHandler = self.errorHandler; var val = self.value; self.value = null; self.callback = noop; if (self.errorHandler) { errorHandler(err, val); } callback.call(self.context, err, result); self.release(self); }; } function queueAsPromised (context, worker, _concurrency) { if (typeof context === 'function') { _concurrency = worker; worker = context; context = null; } function asyncWrapper (arg, cb) { worker.call(this, arg) .then(function (res) { cb(null, res); }, cb); } var queue = fastqueue(context, asyncWrapper, _concurrency); var pushCb = queue.push; var unshiftCb = queue.unshift; queue.push = push; queue.unshift = unshift; queue.drained = drained; return queue function push (value) { var p = new Promise(function (resolve, reject) { pushCb(value, function (err, result) { if (err) { reject(err); return } resolve(result); }); }); // Let's fork the promise chain to // make the error bubble up to the user but // not lead to a unhandledRejection p.catch(noop); return p } function unshift (value) { var p = new Promise(function (resolve, reject) { unshiftCb(value, function (err, result) { if (err) { reject(err); return } resolve(result); }); }); // Let's fork the promise chain to // make the error bubble up to the user but // not lead to a unhandledRejection p.catch(noop); return p } function drained () { if (queue.idle()) { return new Promise(function (resolve) { resolve(); }) } var previousDrain = queue.drain; var p = new Promise(function (resolve) { queue.drain = function () { previousDrain(); resolve(); }; }); return p } } queue.exports = fastqueue; queue.exports.promise = queueAsPromised; return queue.exports; } var common = {}; var hasRequiredCommon; function requireCommon () { if (hasRequiredCommon) return common; hasRequiredCommon = 1; Object.defineProperty(common, "__esModule", { value: true }); common.joinPathSegments = common.replacePathSegmentSeparator = common.isAppliedFilter = common.isFatalError = void 0; function isFatalError(settings, error) { if (settings.errorFilter === null) { return true; } return !settings.errorFilter(error); } common.isFatalError = isFatalError; function isAppliedFilter(filter, value) { return filter === null || filter(value); } common.isAppliedFilter = isAppliedFilter; function replacePathSegmentSeparator(filepath, separator) { return filepath.split(/[/\\]/).join(separator); } common.replacePathSegmentSeparator = replacePathSegmentSeparator; function joinPathSegments(a, b, separator) { if (a === '') { return b; } /** * The correct handling of cases when the first segment is a root (`/`, `C:/`) or UNC path (`//?/C:/`). */ if (a.endsWith(separator)) { return a + b; } return a + separator + b; } common.joinPathSegments = joinPathSegments; return common; } var reader$1 = {}; var hasRequiredReader$1; function requireReader$1 () { if (hasRequiredReader$1) return reader$1; hasRequiredReader$1 = 1; Object.defineProperty(reader$1, "__esModule", { value: true }); const common = requireCommon(); class Reader { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._root = common.replacePathSegmentSeparator(_root, _settings.pathSegmentSeparator); } } reader$1.default = Reader; return reader$1; } var hasRequiredAsync$3; function requireAsync$3 () { if (hasRequiredAsync$3) return async$2; hasRequiredAsync$3 = 1; Object.defineProperty(async$2, "__esModule", { value: true }); const events_1 = require$$0$3; const fsScandir = requireOut$2(); const fastq = requireQueue(); const common = requireCommon(); const reader_1 = requireReader$1(); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); this._settings = _settings; this._scandir = fsScandir.scandir; this._emitter = new events_1.EventEmitter(); this._queue = fastq(this._worker.bind(this), this._settings.concurrency); this._isFatalError = false; this._isDestroyed = false; this._queue.drain = () => { if (!this._isFatalError) { this._emitter.emit('end'); } }; } read() { this._isFatalError = false; this._isDestroyed = false; setImmediate(() => { this._pushToQueue(this._root, this._settings.basePath); }); return this._emitter; } get isDestroyed() { return this._isDestroyed; } destroy() { if (this._isDestroyed) { throw new Error('The reader is already destroyed'); } this._isDestroyed = true; this._queue.killAndDrain(); } onEntry(callback) { this._emitter.on('entry', callback); } onError(callback) { this._emitter.once('error', callback); } onEnd(callback) { this._emitter.once('end', callback); } _pushToQueue(directory, base) { const queueItem = { directory, base }; this._queue.push(queueItem, (error) => { if (error !== null) { this._handleError(error); } }); } _worker(item, done) { this._scandir(item.directory, this._settings.fsScandirSettings, (error, entries) => { if (error !== null) { done(error, undefined); return; } for (const entry of entries) { this._handleEntry(entry, item.base); } done(null, undefined); }); } _handleError(error) { if (this._isDestroyed || !common.isFatalError(this._settings, error)) { return; } this._isFatalError = true; this._isDestroyed = true; this._emitter.emit('error', error); } _handleEntry(entry, base) { if (this._isDestroyed || this._isFatalError) { return; } const fullpath = entry.path; if (base !== undefined) { entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); } if (common.isAppliedFilter(this._settings.entryFilter, entry)) { this._emitEntry(entry); } if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { this._pushToQueue(fullpath, base === undefined ? undefined : entry.path); } } _emitEntry(entry) { this._emitter.emit('entry', entry); } } async$2.default = AsyncReader; return async$2; } var hasRequiredAsync$2; function requireAsync$2 () { if (hasRequiredAsync$2) return async$3; hasRequiredAsync$2 = 1; Object.defineProperty(async$3, "__esModule", { value: true }); const async_1 = requireAsync$3(); class AsyncProvider { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._reader = new async_1.default(this._root, this._settings); this._storage = []; } read(callback) { this._reader.onError((error) => { callFailureCallback(callback, error); }); this._reader.onEntry((entry) => { this._storage.push(entry); }); this._reader.onEnd(() => { callSuccessCallback(callback, this._storage); }); this._reader.read(); } } async$3.default = AsyncProvider; function callFailureCallback(callback, error) { callback(error); } function callSuccessCallback(callback, entries) { callback(null, entries); } return async$3; } var stream$2 = {}; var hasRequiredStream$2; function requireStream$2 () { if (hasRequiredStream$2) return stream$2; hasRequiredStream$2 = 1; Object.defineProperty(stream$2, "__esModule", { value: true }); const stream_1 = require$$0$2; const async_1 = requireAsync$3(); class StreamProvider { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._reader = new async_1.default(this._root, this._settings); this._stream = new stream_1.Readable({ objectMode: true, read: () => { }, destroy: () => { if (!this._reader.isDestroyed) { this._reader.destroy(); } } }); } read() { this._reader.onError((error) => { this._stream.emit('error', error); }); this._reader.onEntry((entry) => { this._stream.push(entry); }); this._reader.onEnd(() => { this._stream.push(null); }); this._reader.read(); return this._stream; } } stream$2.default = StreamProvider; return stream$2; } var sync$3 = {}; var sync$2 = {}; var hasRequiredSync$3; function requireSync$3 () { if (hasRequiredSync$3) return sync$2; hasRequiredSync$3 = 1; Object.defineProperty(sync$2, "__esModule", { value: true }); const fsScandir = requireOut$2(); const common = requireCommon(); const reader_1 = requireReader$1(); class SyncReader extends reader_1.default { constructor() { super(...arguments); this._scandir = fsScandir.scandirSync; this._storage = []; this._queue = new Set(); } read() { this._pushToQueue(this._root, this._settings.basePath); this._handleQueue(); return this._storage; } _pushToQueue(directory, base) { this._queue.add({ directory, base }); } _handleQueue() { for (const item of this._queue.values()) { this._handleDirectory(item.directory, item.base); } } _handleDirectory(directory, base) { try { const entries = this._scandir(directory, this._settings.fsScandirSettings); for (const entry of entries) { this._handleEntry(entry, base); } } catch (error) { this._handleError(error); } } _handleError(error) { if (!common.isFatalError(this._settings, error)) { return; } throw error; } _handleEntry(entry, base) { const fullpath = entry.path; if (base !== undefined) { entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); } if (common.isAppliedFilter(this._settings.entryFilter, entry)) { this._pushToStorage(entry); } if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { this._pushToQueue(fullpath, base === undefined ? undefined : entry.path); } } _pushToStorage(entry) { this._storage.push(entry); } } sync$2.default = SyncReader; return sync$2; } var hasRequiredSync$2; function requireSync$2 () { if (hasRequiredSync$2) return sync$3; hasRequiredSync$2 = 1; Object.defineProperty(sync$3, "__esModule", { value: true }); const sync_1 = requireSync$3(); class SyncProvider { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._reader = new sync_1.default(this._root, this._settings); } read() { return this._reader.read(); } } sync$3.default = SyncProvider; return sync$3; } var settings$1 = {}; var hasRequiredSettings$1; function requireSettings$1 () { if (hasRequiredSettings$1) return settings$1; hasRequiredSettings$1 = 1; Object.defineProperty(settings$1, "__esModule", { value: true }); const path = require$$0$5; const fsScandir = requireOut$2(); class Settings { constructor(_options = {}) { this._options = _options; this.basePath = this._getValue(this._options.basePath, undefined); this.concurrency = this._getValue(this._options.concurrency, Number.POSITIVE_INFINITY); this.deepFilter = this._getValue(this._options.deepFilter, null); this.entryFilter = this._getValue(this._options.entryFilter, null); this.errorFilter = this._getValue(this._options.errorFilter, null); this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); this.fsScandirSettings = new fsScandir.Settings({ followSymbolicLinks: this._options.followSymbolicLinks, fs: this._options.fs, pathSegmentSeparator: this._options.pathSegmentSeparator, stats: this._options.stats, throwErrorOnBrokenSymbolicLink: this._options.throwErrorOnBrokenSymbolicLink }); } _getValue(option, value) { return option !== null && option !== void 0 ? option : value; } } settings$1.default = Settings; return settings$1; } var hasRequiredOut$1; function requireOut$1 () { if (hasRequiredOut$1) return out$3; hasRequiredOut$1 = 1; Object.defineProperty(out$3, "__esModule", { value: true }); out$3.Settings = out$3.walkStream = out$3.walkSync = out$3.walk = void 0; const async_1 = requireAsync$2(); const stream_1 = requireStream$2(); const sync_1 = requireSync$2(); const settings_1 = requireSettings$1(); out$3.Settings = settings_1.default; function walk(directory, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { new async_1.default(directory, getSettings()).read(optionsOrSettingsOrCallback); return; } new async_1.default(directory, getSettings(optionsOrSettingsOrCallback)).read(callback); } out$3.walk = walk; function walkSync(directory, optionsOrSettings) { const settings = getSettings(optionsOrSettings); const provider = new sync_1.default(directory, settings); return provider.read(); } out$3.walkSync = walkSync; function walkStream(directory, optionsOrSettings) { const settings = getSettings(optionsOrSettings); const provider = new stream_1.default(directory, settings); return provider.read(); } out$3.walkStream = walkStream; function getSettings(settingsOrOptions = {}) { if (settingsOrOptions instanceof settings_1.default) { return settingsOrOptions; } return new settings_1.default(settingsOrOptions); } return out$3; } var reader = {}; var hasRequiredReader; function requireReader () { if (hasRequiredReader) return reader; hasRequiredReader = 1; Object.defineProperty(reader, "__esModule", { value: true }); const path = require$$0$5; const fsStat = requireOut$3(); const utils = requireUtils$1(); class Reader { constructor(_settings) { this._settings = _settings; this._fsStatSettings = new fsStat.Settings({ followSymbolicLink: this._settings.followSymbolicLinks, fs: this._settings.fs, throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks }); } _getFullEntryPath(filepath) { return path.resolve(this._settings.cwd, filepath); } _makeEntry(stats, pattern) { const entry = { name: pattern, path: pattern, dirent: utils.fs.createDirentFromStats(pattern, stats) }; if (this._settings.stats) { entry.stats = stats; } return entry; } _isFatalError(error) { return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors; } } reader.default = Reader; return reader; } var stream$1 = {}; var hasRequiredStream$1; function requireStream$1 () { if (hasRequiredStream$1) return stream$1; hasRequiredStream$1 = 1; Object.defineProperty(stream$1, "__esModule", { value: true }); const stream_1 = require$$0$2; const fsStat = requireOut$3(); const fsWalk = requireOut$1(); const reader_1 = requireReader(); class ReaderStream extends reader_1.default { constructor() { super(...arguments); this._walkStream = fsWalk.walkStream; this._stat = fsStat.stat; } dynamic(root, options) { return this._walkStream(root, options); } static(patterns, options) { const filepaths = patterns.map(this._getFullEntryPath, this); const stream = new stream_1.PassThrough({ objectMode: true }); stream._write = (index, _enc, done) => { return this._getEntry(filepaths[index], patterns[index], options) .then((entry) => { if (entry !== null && options.entryFilter(entry)) { stream.push(entry); } if (index === filepaths.length - 1) { stream.end(); } done(); }) .catch(done); }; for (let i = 0; i < filepaths.length; i++) { stream.write(i); } return stream; } _getEntry(filepath, pattern, options) { return this._getStat(filepath) .then((stats) => this._makeEntry(stats, pattern)) .catch((error) => { if (options.errorFilter(error)) { return null; } throw error; }); } _getStat(filepath) { return new Promise((resolve, reject) => { this._stat(filepath, this._fsStatSettings, (error, stats) => { return error === null ? resolve(stats) : reject(error); }); }); } } stream$1.default = ReaderStream; return stream$1; } var hasRequiredAsync$1; function requireAsync$1 () { if (hasRequiredAsync$1) return async$4; hasRequiredAsync$1 = 1; Object.defineProperty(async$4, "__esModule", { value: true }); const fsWalk = requireOut$1(); const reader_1 = requireReader(); const stream_1 = requireStream$1(); class ReaderAsync extends reader_1.default { constructor() { super(...arguments); this._walkAsync = fsWalk.walk; this._readerStream = new stream_1.default(this._settings); } dynamic(root, options) { return new Promise((resolve, reject) => { this._walkAsync(root, options, (error, entries) => { if (error === null) { resolve(entries); } else { reject(error); } }); }); } async static(patterns, options) { const entries = []; const stream = this._readerStream.static(patterns, options); // After #235, replace it with an asynchronous iterator. return new Promise((resolve, reject) => { stream.once('error', reject); stream.on('data', (entry) => entries.push(entry)); stream.once('end', () => resolve(entries)); }); } } async$4.default = ReaderAsync; return async$4; } var provider = {}; var deep = {}; var partial = {}; var matcher = {}; var hasRequiredMatcher; function requireMatcher () { if (hasRequiredMatcher) return matcher; hasRequiredMatcher = 1; Object.defineProperty(matcher, "__esModule", { value: true }); const utils = requireUtils$1(); class Matcher { constructor(_patterns, _settings, _micromatchOptions) { this._patterns = _patterns; this._settings = _settings; this._micromatchOptions = _micromatchOptions; this._storage = []; this._fillStorage(); } _fillStorage() { for (const pattern of this._patterns) { const segments = this._getPatternSegments(pattern); const sections = this._splitSegmentsIntoSections(segments); this._storage.push({ complete: sections.length <= 1, pattern, segments, sections }); } } _getPatternSegments(pattern) { const parts = utils.pattern.getPatternParts(pattern, this._micromatchOptions); return parts.map((part) => { const dynamic = utils.pattern.isDynamicPattern(part, this._settings); if (!dynamic) { return { dynamic: false, pattern: part }; } return { dynamic: true, pattern: part, patternRe: utils.pattern.makeRe(part, this._micromatchOptions) }; }); } _splitSegmentsIntoSections(segments) { return utils.array.splitWhen(segments, (segment) => segment.dynamic && utils.pattern.hasGlobStar(segment.pattern)); } } matcher.default = Matcher; return matcher; } var hasRequiredPartial; function requirePartial () { if (hasRequiredPartial) return partial; hasRequiredPartial = 1; Object.defineProperty(partial, "__esModule", { value: true }); const matcher_1 = requireMatcher(); class PartialMatcher extends matcher_1.default { match(filepath) { const parts = filepath.split('/'); const levels = parts.length; const patterns = this._storage.filter((info) => !info.complete || info.segments.length > levels); for (const pattern of patterns) { const section = pattern.sections[0]; /** * In this case, the pattern has a globstar and we must read all directories unconditionally, * but only if the level has reached the end of the first group. * * fixtures/{a,b}/** * ^ true/false ^ always true */ if (!pattern.complete && levels > section.length) { return true; } const match = parts.every((part, index) => { const segment = pattern.segments[index]; if (segment.dynamic && segment.patternRe.test(part)) { return true; } if (!segment.dynamic && segment.pattern === part) { return true; } return false; }); if (match) { return true; } } return false; } } partial.default = PartialMatcher; return partial; } var hasRequiredDeep; function requireDeep () { if (hasRequiredDeep) return deep; hasRequiredDeep = 1; Object.defineProperty(deep, "__esModule", { value: true }); const utils = requireUtils$1(); const partial_1 = requirePartial(); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; this._micromatchOptions = _micromatchOptions; } getFilter(basePath, positive, negative) { const matcher = this._getMatcher(positive); const negativeRe = this._getNegativePatternsRe(negative); return (entry) => this._filter(basePath, entry, matcher, negativeRe); } _getMatcher(patterns) { return new partial_1.default(patterns, this._settings, this._micromatchOptions); } _getNegativePatternsRe(patterns) { const affectDepthOfReadingPatterns = patterns.filter(utils.pattern.isAffectDepthOfReadingPattern); return utils.pattern.convertPatternsToRe(affectDepthOfReadingPatterns, this._micromatchOptions); } _filter(basePath, entry, matcher, negativeRe) { if (this._isSkippedByDeep(basePath, entry.path)) { return false; } if (this._isSkippedSymbolicLink(entry)) { return false; } const filepath = utils.path.removeLeadingDotSegment(entry.path); if (this._isSkippedByPositivePatterns(filepath, matcher)) { return false; } return this._isSkippedByNegativePatterns(filepath, negativeRe); } _isSkippedByDeep(basePath, entryPath) { /** * Avoid unnecessary depth calculations when it doesn't matter. */ if (this._settings.deep === Infinity) { return false; } return this._getEntryLevel(basePath, entryPath) >= this._settings.deep; } _getEntryLevel(basePath, entryPath) { const entryPathDepth = entryPath.split('/').length; if (basePath === '') { return entryPathDepth; } const basePathDepth = basePath.split('/').length; return entryPathDepth - basePathDepth; } _isSkippedSymbolicLink(entry) { return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); } _isSkippedByPositivePatterns(entryPath, matcher) { return !this._settings.baseNameMatch && !matcher.match(entryPath); } _isSkippedByNegativePatterns(entryPath, patternsRe) { return !utils.pattern.matchAny(entryPath, patternsRe); } } deep.default = DeepFilter; return deep; } var entry$1 = {}; var hasRequiredEntry$1; function requireEntry$1 () { if (hasRequiredEntry$1) return entry$1; hasRequiredEntry$1 = 1; Object.defineProperty(entry$1, "__esModule", { value: true }); const utils = requireUtils$1(); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; this._micromatchOptions = _micromatchOptions; this.index = new Map(); } getFilter(positive, negative) { const positiveRe = utils.pattern.convertPatternsToRe(positive, this._micromatchOptions); const negativeRe = utils.pattern.convertPatternsToRe(negative, Object.assign(Object.assign({}, this._micromatchOptions), { dot: true })); return (entry) => this._filter(entry, positiveRe, negativeRe); } _filter(entry, positiveRe, negativeRe) { const filepath = utils.path.removeLeadingDotSegment(entry.path); if (this._settings.unique && this._isDuplicateEntry(filepath)) { return false; } if (this._onlyFileFilter(entry) || this._onlyDirectoryFilter(entry)) { return false; } if (this._isSkippedByAbsoluteNegativePatterns(filepath, negativeRe)) { return false; } const isDirectory = entry.dirent.isDirectory(); const isMatched = this._isMatchToPatterns(filepath, positiveRe, isDirectory) && !this._isMatchToPatterns(filepath, negativeRe, isDirectory); if (this._settings.unique && isMatched) { this._createIndexRecord(filepath); } return isMatched; } _isDuplicateEntry(filepath) { return this.index.has(filepath); } _createIndexRecord(filepath) { this.index.set(filepath, undefined); } _onlyFileFilter(entry) { return this._settings.onlyFiles && !entry.dirent.isFile(); } _onlyDirectoryFilter(entry) { return this._settings.onlyDirectories && !entry.dirent.isDirectory(); } _isSkippedByAbsoluteNegativePatterns(entryPath, patternsRe) { if (!this._settings.absolute) { return false; } const fullpath = utils.path.makeAbsolute(this._settings.cwd, entryPath); return utils.pattern.matchAny(fullpath, patternsRe); } _isMatchToPatterns(filepath, patternsRe, isDirectory) { // Trying to match files and directories by patterns. const isMatched = utils.pattern.matchAny(filepath, patternsRe); // A pattern with a trailling slash can be used for directory matching. // To apply such pattern, we need to add a tralling slash to the path. if (!isMatched && isDirectory) { return utils.pattern.matchAny(filepath + '/', patternsRe); } return isMatched; } } entry$1.default = EntryFilter; return entry$1; } var error = {}; var hasRequiredError; function requireError () { if (hasRequiredError) return error; hasRequiredError = 1; Object.defineProperty(error, "__esModule", { value: true }); const utils = requireUtils$1(); class ErrorFilter { constructor(_settings) { this._settings = _settings; } getFilter() { return (error) => this._isNonFatalError(error); } _isNonFatalError(error) { return utils.errno.isEnoentCodeError(error) || this._settings.suppressErrors; } } error.default = ErrorFilter; return error; } var entry = {}; var hasRequiredEntry; function requireEntry () { if (hasRequiredEntry) return entry; hasRequiredEntry = 1; Object.defineProperty(entry, "__esModule", { value: true }); const utils = requireUtils$1(); class EntryTransformer { constructor(_settings) { this._settings = _settings; } getTransformer() { return (entry) => this._transform(entry); } _transform(entry) { let filepath = entry.path; if (this._settings.absolute) { filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); filepath = utils.path.unixify(filepath); } if (this._settings.markDirectories && entry.dirent.isDirectory()) { filepath += '/'; } if (!this._settings.objectMode) { return filepath; } return Object.assign(Object.assign({}, entry), { path: filepath }); } } entry.default = EntryTransformer; return entry; } var hasRequiredProvider; function requireProvider () { if (hasRequiredProvider) return provider; hasRequiredProvider = 1; Object.defineProperty(provider, "__esModule", { value: true }); const path = require$$0$5; const deep_1 = requireDeep(); const entry_1 = requireEntry$1(); const error_1 = requireError(); const entry_2 = requireEntry(); class Provider { constructor(_settings) { this._settings = _settings; this.errorFilter = new error_1.default(this._settings); this.entryFilter = new entry_1.default(this._settings, this._getMicromatchOptions()); this.deepFilter = new deep_1.default(this._settings, this._getMicromatchOptions()); this.entryTransformer = new entry_2.default(this._settings); } _getRootDirectory(task) { return path.resolve(this._settings.cwd, task.base); } _getReaderOptions(task) { const basePath = task.base === '.' ? '' : task.base; return { basePath, pathSegmentSeparator: '/', concurrency: this._settings.concurrency, deepFilter: this.deepFilter.getFilter(basePath, task.positive, task.negative), entryFilter: this.entryFilter.getFilter(task.positive, task.negative), errorFilter: this.errorFilter.getFilter(), followSymbolicLinks: this._settings.followSymbolicLinks, fs: this._settings.fs, stats: this._settings.stats, throwErrorOnBrokenSymbolicLink: this._settings.throwErrorOnBrokenSymbolicLink, transform: this.entryTransformer.getTransformer() }; } _getMicromatchOptions() { return { dot: this._settings.dot, matchBase: this._settings.baseNameMatch, nobrace: !this._settings.braceExpansion, nocase: !this._settings.caseSensitiveMatch, noext: !this._settings.extglob, noglobstar: !this._settings.globstar, posix: true, strictSlashes: false }; } } provider.default = Provider; return provider; } var hasRequiredAsync; function requireAsync () { if (hasRequiredAsync) return async$5; hasRequiredAsync = 1; Object.defineProperty(async$5, "__esModule", { value: true }); const async_1 = requireAsync$1(); const provider_1 = requireProvider(); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); this._reader = new async_1.default(this._settings); } async read(task) { const root = this._getRootDirectory(task); const options = this._getReaderOptions(task); const entries = await this.api(root, task, options); return entries.map((entry) => options.transform(entry)); } api(root, task, options) { if (task.dynamic) { return this._reader.dynamic(root, options); } return this._reader.static(task.patterns, options); } } async$5.default = ProviderAsync; return async$5; } var stream = {}; var hasRequiredStream; function requireStream () { if (hasRequiredStream) return stream; hasRequiredStream = 1; Object.defineProperty(stream, "__esModule", { value: true }); const stream_1 = require$$0$2; const stream_2 = requireStream$1(); const provider_1 = requireProvider(); class ProviderStream extends provider_1.default { constructor() { super(...arguments); this._reader = new stream_2.default(this._settings); } read(task) { const root = this._getRootDirectory(task); const options = this._getReaderOptions(task); const source = this.api(root, task, options); const destination = new stream_1.Readable({ objectMode: true, read: () => { } }); source .once('error', (error) => destination.emit('error', error)) .on('data', (entry) => destination.emit('data', options.transform(entry))) .once('end', () => destination.emit('end')); destination .once('close', () => source.destroy()); return destination; } api(root, task, options) { if (task.dynamic) { return this._reader.dynamic(root, options); } return this._reader.static(task.patterns, options); } } stream.default = ProviderStream; return stream; } var sync$1 = {}; var sync = {}; var hasRequiredSync$1; function requireSync$1 () { if (hasRequiredSync$1) return sync; hasRequiredSync$1 = 1; Object.defineProperty(sync, "__esModule", { value: true }); const fsStat = requireOut$3(); const fsWalk = requireOut$1(); const reader_1 = requireReader(); class ReaderSync extends reader_1.default { constructor() { super(...arguments); this._walkSync = fsWalk.walkSync; this._statSync = fsStat.statSync; } dynamic(root, options) { return this._walkSync(root, options); } static(patterns, options) { const entries = []; for (const pattern of patterns) { const filepath = this._getFullEntryPath(pattern); const entry = this._getEntry(filepath, pattern, options); if (entry === null || !options.entryFilter(entry)) { continue; } entries.push(entry); } return entries; } _getEntry(filepath, pattern, options) { try { const stats = this._getStat(filepath); return this._makeEntry(stats, pattern); } catch (error) { if (options.errorFilter(error)) { return null; } throw error; } } _getStat(filepath) { return this._statSync(filepath, this._fsStatSettings); } } sync.default = ReaderSync; return sync; } var hasRequiredSync; function requireSync () { if (hasRequiredSync) return sync$1; hasRequiredSync = 1; Object.defineProperty(sync$1, "__esModule", { value: true }); const sync_1 = requireSync$1(); const provider_1 = requireProvider(); class ProviderSync extends provider_1.default { constructor() { super(...arguments); this._reader = new sync_1.default(this._settings); } read(task) { const root = this._getRootDirectory(task); const options = this._getReaderOptions(task); const entries = this.api(root, task, options); return entries.map(options.transform); } api(root, task, options) { if (task.dynamic) { return this._reader.dynamic(root, options); } return this._reader.static(task.patterns, options); } } sync$1.default = ProviderSync; return sync$1; } var settings = {}; var hasRequiredSettings; function requireSettings () { if (hasRequiredSettings) return settings; hasRequiredSettings = 1; (function (exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_FILE_SYSTEM_ADAPTER = void 0; const fs = require$$0$6; const os = require$$0$4; /** * The `os.cpus` method can return zero. We expect the number of cores to be greater than zero. * https://github.com/nodejs/node/blob/7faeddf23a98c53896f8b574a6e66589e8fb1eb8/lib/os.js#L106-L107 */ const CPU_COUNT = Math.max(os.cpus().length, 1); exports.DEFAULT_FILE_SYSTEM_ADAPTER = { lstat: fs.lstat, lstatSync: fs.lstatSync, stat: fs.stat, statSync: fs.statSync, readdir: fs.readdir, readdirSync: fs.readdirSync }; class Settings { constructor(_options = {}) { this._options = _options; this.absolute = this._getValue(this._options.absolute, false); this.baseNameMatch = this._getValue(this._options.baseNameMatch, false); this.braceExpansion = this._getValue(this._options.braceExpansion, true); this.caseSensitiveMatch = this._getValue(this._options.caseSensitiveMatch, true); this.concurrency = this._getValue(this._options.concurrency, CPU_COUNT); this.cwd = this._getValue(this._options.cwd, process.cwd()); this.deep = this._getValue(this._options.deep, Infinity); this.dot = this._getValue(this._options.dot, false); this.extglob = this._getValue(this._options.extglob, true); this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, true); this.fs = this._getFileSystemMethods(this._options.fs); this.globstar = this._getValue(this._options.globstar, true); this.ignore = this._getValue(this._options.ignore, []); this.markDirectories = this._getValue(this._options.markDirectories, false); this.objectMode = this._getValue(this._options.objectMode, false); this.onlyDirectories = this._getValue(this._options.onlyDirectories, false); this.onlyFiles = this._getValue(this._options.onlyFiles, true); this.stats = this._getValue(this._options.stats, false); this.suppressErrors = this._getValue(this._options.suppressErrors, false); this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, false); this.unique = this._getValue(this._options.unique, true); if (this.onlyDirectories) { this.onlyFiles = false; } if (this.stats) { this.objectMode = true; } // Remove the cast to the array in the next major (#404). this.ignore = [].concat(this.ignore); } _getValue(option, value) { return option === undefined ? value : option; } _getFileSystemMethods(methods = {}) { return Object.assign(Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER), methods); } } exports.default = Settings; } (settings)); return settings; } var out; var hasRequiredOut; function requireOut () { if (hasRequiredOut) return out; hasRequiredOut = 1; const taskManager = requireTasks(); const async_1 = requireAsync(); const stream_1 = requireStream(); const sync_1 = requireSync(); const settings_1 = requireSettings(); const utils = requireUtils$1(); async function FastGlob(source, options) { assertPatternsInput(source); const works = getWorks(source, async_1.default, options); const result = await Promise.all(works); return utils.array.flatten(result); } // https://github.com/typescript-eslint/typescript-eslint/issues/60 // eslint-disable-next-line no-redeclare (function (FastGlob) { FastGlob.glob = FastGlob; FastGlob.globSync = sync; FastGlob.globStream = stream; FastGlob.async = FastGlob; function sync(source, options) { assertPatternsInput(source); const works = getWorks(source, sync_1.default, options); return utils.array.flatten(works); } FastGlob.sync = sync; function stream(source, options) { assertPatternsInput(source); const works = getWorks(source, stream_1.default, options); /** * The stream returned by the provider cannot work with an asynchronous iterator. * To support asynchronous iterators, regardless of the number of tasks, we always multiplex streams. * This affects performance (+25%). I don't see best solution right now. */ return utils.stream.merge(works); } FastGlob.stream = stream; function generateTasks(source, options) { assertPatternsInput(source); const patterns = [].concat(source); const settings = new settings_1.default(options); return taskManager.generate(patterns, settings); } FastGlob.generateTasks = generateTasks; function isDynamicPattern(source, options) { assertPatternsInput(source); const settings = new settings_1.default(options); return utils.pattern.isDynamicPattern(source, settings); } FastGlob.isDynamicPattern = isDynamicPattern; function escapePath(source) { assertPatternsInput(source); return utils.path.escape(source); } FastGlob.escapePath = escapePath; function convertPathToPattern(source) { assertPatternsInput(source); return utils.path.convertPathToPattern(source); } FastGlob.convertPathToPattern = convertPathToPattern; (function (posix) { function escapePath(source) { assertPatternsInput(source); return utils.path.escapePosixPath(source); } posix.escapePath = escapePath; function convertPathToPattern(source) { assertPatternsInput(source); return utils.path.convertPosixPathToPattern(source); } posix.convertPathToPattern = convertPathToPattern; })(FastGlob.posix || (FastGlob.posix = {})); (function (win32) { function escapePath(source) { assertPatternsInput(source); return utils.path.escapeWindowsPath(source); } win32.escapePath = escapePath; function convertPathToPattern(source) { assertPatternsInput(source); return utils.path.convertWindowsPathToPattern(source); } win32.convertPathToPattern = convertPathToPattern; })(FastGlob.win32 || (FastGlob.win32 = {})); })(FastGlob || (FastGlob = {})); function getWorks(source, _Provider, options) { const patterns = [].concat(source); const settings = new settings_1.default(options); const tasks = taskManager.generate(patterns, settings); const provider = new _Provider(settings); return tasks.map(provider.read, provider); } function assertPatternsInput(input) { const source = [].concat(input); const isValidSource = source.every((item) => utils.string.isString(item) && !utils.string.isEmpty(item)); if (!isValidSource) { throw new TypeError('Patterns must be a string (non empty) or an array of strings'); } } out = FastGlob; return out; } var outExports = requireOut(); var fg = /*@__PURE__*/getDefaultExportFromCjs(outExports); function serializeConfig(config, coreConfig, viteConfig) { const optimizer = config.deps?.optimizer; const poolOptions = config.poolOptions; const isolate = viteConfig?.test?.isolate; return { // TODO: remove functions from environmentOptions environmentOptions: config.environmentOptions, mode: config.mode, isolate: config.isolate, base: config.base, logHeapUsage: config.logHeapUsage, runner: config.runner, bail: config.bail, defines: config.defines, chaiConfig: config.chaiConfig, setupFiles: config.setupFiles, allowOnly: config.allowOnly, testTimeout: config.testTimeout, testNamePattern: config.testNamePattern, hookTimeout: config.hookTimeout, clearMocks: config.clearMocks, mockReset: config.mockReset, restoreMocks: config.restoreMocks, unstubEnvs: config.unstubEnvs, unstubGlobals: config.unstubGlobals, maxConcurrency: config.maxConcurrency, pool: config.pool, expect: config.expect, snapshotSerializers: config.snapshotSerializers, diff: config.diff, retry: config.retry, disableConsoleIntercept: config.disableConsoleIntercept, root: config.root, name: config.name, globals: config.globals, snapshotEnvironment: config.snapshotEnvironment, passWithNoTests: config.passWithNoTests, coverage: ((coverage) => { const htmlReporter = coverage.reporter.find(([reporterName]) => reporterName === "html"); const subdir = htmlReporter && htmlReporter[1]?.subdir; return { reportsDirectory: coverage.reportsDirectory, provider: coverage.provider, enabled: coverage.enabled, htmlReporter: htmlReporter ? { subdir } : void 0, customProviderModule: "customProviderModule" in coverage ? coverage.customProviderModule : void 0 }; })(config.coverage), fakeTimers: config.fakeTimers, poolOptions: { forks: { singleFork: poolOptions?.forks?.singleFork ?? coreConfig.poolOptions?.forks?.singleFork ?? false, isolate: poolOptions?.forks?.isolate ?? isolate ?? coreConfig.poolOptions?.forks?.isolate ?? true }, threads: { singleThread: poolOptions?.threads?.singleThread ?? coreConfig.poolOptions?.threads?.singleThread ?? false, isolate: poolOptions?.threads?.isolate ?? isolate ?? coreConfig.poolOptions?.threads?.isolate ?? true }, vmThreads: { singleThread: poolOptions?.vmThreads?.singleThread ?? coreConfig.poolOptions?.vmThreads?.singleThread ?? false }, vmForks: { singleFork: poolOptions?.vmForks?.singleFork ?? coreConfig.poolOptions?.vmForks?.singleFork ?? false } }, deps: { web: config.deps.web || {}, optimizer: { web: { enabled: optimizer?.web?.enabled ?? true }, ssr: { enabled: optimizer?.ssr?.enabled ?? true } }, interopDefault: config.deps.interopDefault, moduleDirectories: config.deps.moduleDirectories }, snapshotOptions: { // TODO: store it differently, not on the config snapshotEnvironment: void 0, updateSnapshot: coreConfig.snapshotOptions.updateSnapshot, snapshotFormat: { ...coreConfig.snapshotOptions.snapshotFormat, compareKeys: void 0 }, expand: config.snapshotOptions.expand ?? coreConfig.snapshotOptions.expand }, sequence: { shuffle: coreConfig.sequence.shuffle, concurrent: coreConfig.sequence.concurrent, seed: coreConfig.sequence.seed, hooks: coreConfig.sequence.hooks, setupFiles: coreConfig.sequence.setupFiles }, inspect: coreConfig.inspect, inspectBrk: coreConfig.inspectBrk, inspector: coreConfig.inspector, watch: config.watch, includeTaskLocation: config.includeTaskLocation ?? coreConfig.includeTaskLocation, env: { ...viteConfig?.env, ...config.env }, browser: ((browser) => { return { name: browser.name, headless: browser.headless, isolate: browser.isolate, fileParallelism: browser.fileParallelism, ui: browser.ui, viewport: browser.viewport, screenshotFailures: browser.screenshotFailures, locators: { testIdAttribute: browser.locators.testIdAttribute } }; })(config.browser), standalone: config.standalone, printConsoleTrace: config.printConsoleTrace ?? coreConfig.printConsoleTrace, benchmark: config.benchmark && { includeSamples: config.benchmark.includeSamples } }; } async function loadGlobalSetupFiles(runner, globalSetup) { const globalSetupFiles = toArray(globalSetup); return Promise.all( globalSetupFiles.map((file) => loadGlobalSetupFile(file, runner)) ); } async function loadGlobalSetupFile(file, runner) { const m = await runner.executeFile(file); for (const exp of ["default", "setup", "teardown"]) { if (m[exp] != null && typeof m[exp] !== "function") { throw new Error( `invalid export in globalSetup file ${file}: ${exp} must be a function` ); } } if (m.default) { return { file, setup: m.default }; } else if (m.setup || m.teardown) { return { file, setup: m.setup, teardown: m.teardown }; } else { throw new Error( `invalid globalSetup file ${file}. Must export setup, teardown or have a default export` ); } } function CoverageTransform(ctx) { return { name: "vitest:coverage-transform", transform(srcCode, id) { return ctx.coverageProvider?.onFileTransform?.( srcCode, normalizeRequestId(id), this ); } }; } function MocksPlugins(options = {}) { const normalizedDistDir = normalize(distDir); return [ hoistMocksPlugin({ filter(id) { if (id.includes(normalizedDistDir)) { return false; } if (options.filter) { return options.filter(id); } return true; }, codeFrameGenerator(node, id, code) { return generateCodeFrame( code, 4, node.start + 1 ); } }), automockPlugin() ]; } function generateCssFilenameHash(filepath) { return hash("md5", filepath, "hex").slice(0, 6); } function generateScopedClassName(strategy, name, filename) { if (strategy === "scoped") { return null; } if (strategy === "non-scoped") { return name; } const hash2 = generateCssFilenameHash(filename); return `_${name}_${hash2}`; } const LogLevels = { silent: 0, error: 1, warn: 2, info: 3 }; function clearScreen(logger) { const repeatCount = process.stdout.rows - 2; const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : ""; logger.clearScreen(blank); } let lastType; let lastMsg; let sameCount = 0; let timeFormatter; function getTimeFormatter() { timeFormatter ??= new Intl.DateTimeFormat(void 0, { hour: "numeric", minute: "numeric", second: "numeric" }); return timeFormatter; } function createViteLogger(console, level = "info", options = {}) { const loggedErrors = /* @__PURE__ */ new WeakSet(); const { prefix = "[vite]", allowClearScreen = true } = options; const thresh = LogLevels[level]; const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI; const clear = canClearScreen ? clearScreen : () => { }; function format(type, msg, options2 = {}) { if (options2.timestamp) { let tag = ""; if (type === "info") { tag = c.cyan(c.bold(prefix)); } else if (type === "warn") { tag = c.yellow(c.bold(prefix)); } else { tag = c.red(c.bold(prefix)); } const environment = options2.environment ? `${options2.environment} ` : ""; return `${c.dim(getTimeFormatter().format(/* @__PURE__ */ new Date()))} ${tag} ${environment}${msg}`; } else { return msg; } } function output(type, msg, options2 = {}) { if (thresh >= LogLevels[type]) { const method = type === "info" ? "log" : type; if (options2.error) { loggedErrors.add(options2.error); } if (canClearScreen) { if (type === lastType && msg === lastMsg) { sameCount++; clear(console); console[method]( format(type, msg, options2), c.yellow(`(x${sameCount + 1})`) ); } else { sameCount = 0; lastMsg = msg; lastType = type; if (options2.clear) { clear(console); } console[method](format(type, msg, options2)); } } else { console[method](format(type, msg, options2)); } } } const warnedMessages = /* @__PURE__ */ new Set(); const logger = { hasWarned: false, info(msg, opts) { output("info", msg, opts); }, warn(msg, opts) { logger.hasWarned = true; output("warn", msg, opts); }, warnOnce(msg, opts) { if (warnedMessages.has(msg)) { return; } logger.hasWarned = true; output("warn", msg, opts); warnedMessages.add(msg); }, error(msg, opts) { logger.hasWarned = true; output("error", msg, opts); }, clearScreen(type) { if (thresh >= LogLevels[type]) { clear(console); } }, hasErrorLogged(error) { return loggedErrors.has(error); } }; return logger; } function silenceImportViteIgnoreWarning(logger) { return { ...logger, warn(msg, options) { if (msg.includes("The above dynamic import cannot be analyzed by Vite")) { return; } logger.warn(msg, options); } }; } const cssLangs = "\\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?)"; const cssLangRE = new RegExp(cssLangs); const cssModuleRE = new RegExp(`\\.module${cssLangs}`); const cssInlineRE = /[?&]inline(?:&|$)/; function isCSS(id) { return cssLangRE.test(id); } function isCSSModule(id) { return cssModuleRE.test(id); } function isInline(id) { return cssInlineRE.test(id); } function getCSSModuleProxyReturn(strategy, filename) { if (strategy === "non-scoped") { return "style"; } const hash = generateCssFilenameHash(filename); return `\`_\${style}_${hash}\``; } function CSSEnablerPlugin(ctx) { const shouldProcessCSS = (id) => { const { css } = ctx.config; if (typeof css === "boolean") { return css; } if (toArray(css.exclude).some((re) => re.test(id))) { return false; } if (toArray(css.include).some((re) => re.test(id))) { return true; } return false; }; return [ { name: "vitest:css-disable", enforce: "pre", transform(code, id) { if (!isCSS(id)) { return; } if (!shouldProcessCSS(id)) { return { code: "" }; } } }, { name: "vitest:css-empty-post", enforce: "post", transform(_, id) { if (!isCSS(id) || shouldProcessCSS(id)) { return; } if (isCSSModule(id) && !isInline(id)) { const scopeStrategy = typeof ctx.config.css !== "boolean" && ctx.config.css.modules?.classNameStrategy || "stable"; const proxyReturn = getCSSModuleProxyReturn( scopeStrategy, relative(ctx.config.root, id) ); const code = `export default new Proxy(Object.create(null), { get(_, style) { return ${proxyReturn}; }, })`; return { code }; } return { code: 'export default ""' }; } } ]; } var jsTokens_1; var hasRequiredJsTokens; function requireJsTokens () { if (hasRequiredJsTokens) return jsTokens_1; hasRequiredJsTokens = 1; // Copyright 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Simon Lydell // License: MIT. var HashbangComment, Identifier, JSXIdentifier, JSXPunctuator, JSXString, JSXText, KeywordsWithExpressionAfter, KeywordsWithNoLineTerminatorAfter, LineTerminatorSequence, MultiLineComment, Newline, NumericLiteral, Punctuator, RegularExpressionLiteral, SingleLineComment, StringLiteral, Template, TokensNotPrecedingObjectLiteral, TokensPrecedingExpression, WhiteSpace; RegularExpressionLiteral = /\/(?![*\/])(?:\[(?:[^\]\\\n\r\u2028\u2029]+|\\.)*\]|[^\/\\\n\r\u2028\u2029]+|\\.)*(\/[$_\u200C\u200D\p{ID_Continue}]*|\\)?/yu; Punctuator = /--|\+\+|=>|\.{3}|\??\.(?!\d)|(?:&&|\|\||\?\?|[+\-%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2}|\/(?![\/*]))=?|[?~,:;[\](){}]/y; Identifier = /(\x23?)(?=[$_\p{ID_Start}\\])(?:[$_\u200C\u200D\p{ID_Continue}]+|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+/yu; StringLiteral = /(['"])(?:[^'"\\\n\r]+|(?!\1)['"]|\\(?:\r\n|[^]))*(\1)?/y; NumericLiteral = /(?:0[xX][\da-fA-F](?:_?[\da-fA-F])*|0[oO][0-7](?:_?[0-7])*|0[bB][01](?:_?[01])*)n?|0n|[1-9](?:_?\d)*n|(?:(?:0(?!\d)|0\d*[89]\d*|[1-9](?:_?\d)*)(?:\.(?:\d(?:_?\d)*)?)?|\.\d(?:_?\d)*)(?:[eE][+-]?\d(?:_?\d)*)?|0[0-7]+/y; Template = /[`}](?:[^`\\$]+|\\[^]|\$(?!\{))*(`|\$\{)?/y; WhiteSpace = /[\t\v\f\ufeff\p{Zs}]+/yu; LineTerminatorSequence = /\r?\n|[\r\u2028\u2029]/y; MultiLineComment = /\/\*(?:[^*]+|\*(?!\/))*(\*\/)?/y; SingleLineComment = /\/\/.*/y; HashbangComment = /^#!.*/; JSXPunctuator = /[<>.:={}]|\/(?![\/*])/y; JSXIdentifier = /[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}-]*/yu; JSXString = /(['"])(?:[^'"]+|(?!\1)['"])*(\1)?/y; JSXText = /[^<>{}]+/y; TokensPrecedingExpression = /^(?:[\/+-]|\.{3}|\?(?:InterpolationIn(?:JSX|Template)|NoLineTerminatorHere|NonExpressionParenEnd|UnaryIncDec))?$|[{}([,;<>=*%&|^!~?:]$/; TokensNotPrecedingObjectLiteral = /^(?:=>|[;\]){}]|else|\?(?:NoLineTerminatorHere|NonExpressionParenEnd))?$/; KeywordsWithExpressionAfter = /^(?:await|case|default|delete|do|else|instanceof|new|return|throw|typeof|void|yield)$/; KeywordsWithNoLineTerminatorAfter = /^(?:return|throw|yield)$/; Newline = RegExp(LineTerminatorSequence.source); jsTokens_1 = function*(input, {jsx = false} = {}) { var braces, firstCodePoint, isExpression, lastIndex, lastSignificantToken, length, match, mode, nextLastIndex, nextLastSignificantToken, parenNesting, postfixIncDec, punctuator, stack; ({length} = input); lastIndex = 0; lastSignificantToken = ""; stack = [ {tag: "JS"} ]; braces = []; parenNesting = 0; postfixIncDec = false; if (match = HashbangComment.exec(input)) { yield ({ type: "HashbangComment", value: match[0] }); lastIndex = match[0].length; } while (lastIndex < length) { mode = stack[stack.length - 1]; switch (mode.tag) { case "JS": case "JSNonExpressionParen": case "InterpolationInTemplate": case "InterpolationInJSX": if (input[lastIndex] === "/" && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken))) { RegularExpressionLiteral.lastIndex = lastIndex; if (match = RegularExpressionLiteral.exec(input)) { lastIndex = RegularExpressionLiteral.lastIndex; lastSignificantToken = match[0]; postfixIncDec = true; yield ({ type: "RegularExpressionLiteral", value: match[0], closed: match[1] !== void 0 && match[1] !== "\\" }); continue; } } Punctuator.lastIndex = lastIndex; if (match = Punctuator.exec(input)) { punctuator = match[0]; nextLastIndex = Punctuator.lastIndex; nextLastSignificantToken = punctuator; switch (punctuator) { case "(": if (lastSignificantToken === "?NonExpressionParenKeyword") { stack.push({ tag: "JSNonExpressionParen", nesting: parenNesting }); } parenNesting++; postfixIncDec = false; break; case ")": parenNesting--; postfixIncDec = true; if (mode.tag === "JSNonExpressionParen" && parenNesting === mode.nesting) { stack.pop(); nextLastSignificantToken = "?NonExpressionParenEnd"; postfixIncDec = false; } break; case "{": Punctuator.lastIndex = 0; isExpression = !TokensNotPrecedingObjectLiteral.test(lastSignificantToken) && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken)); braces.push(isExpression); postfixIncDec = false; break; case "}": switch (mode.tag) { case "InterpolationInTemplate": if (braces.length === mode.nesting) { Template.lastIndex = lastIndex; match = Template.exec(input); lastIndex = Template.lastIndex; lastSignificantToken = match[0]; if (match[1] === "${") { lastSignificantToken = "?InterpolationInTemplate"; postfixIncDec = false; yield ({ type: "TemplateMiddle", value: match[0] }); } else { stack.pop(); postfixIncDec = true; yield ({ type: "TemplateTail", value: match[0], closed: match[1] === "`" }); } continue; } break; case "InterpolationInJSX": if (braces.length === mode.nesting) { stack.pop(); lastIndex += 1; lastSignificantToken = "}"; yield ({ type: "JSXPunctuator", value: "}" }); continue; } } postfixIncDec = braces.pop(); nextLastSignificantToken = postfixIncDec ? "?ExpressionBraceEnd" : "}"; break; case "]": postfixIncDec = true; break; case "++": case "--": nextLastSignificantToken = postfixIncDec ? "?PostfixIncDec" : "?UnaryIncDec"; break; case "<": if (jsx && (TokensPrecedingExpression.test(lastSignificantToken) || KeywordsWithExpressionAfter.test(lastSignificantToken))) { stack.push({tag: "JSXTag"}); lastIndex += 1; lastSignificantToken = "<"; yield ({ type: "JSXPunctuator", value: punctuator }); continue; } postfixIncDec = false; break; default: postfixIncDec = false; } lastIndex = nextLastIndex; lastSignificantToken = nextLastSignificantToken; yield ({ type: "Punctuator", value: punctuator }); continue; } Identifier.lastIndex = lastIndex; if (match = Identifier.exec(input)) { lastIndex = Identifier.lastIndex; nextLastSignificantToken = match[0]; switch (match[0]) { case "for": case "if": case "while": case "with": if (lastSignificantToken !== "." && lastSignificantToken !== "?.") { nextLastSignificantToken = "?NonExpressionParenKeyword"; } } lastSignificantToken = nextLastSignificantToken; postfixIncDec = !KeywordsWithExpressionAfter.test(match[0]); yield ({ type: match[1] === "#" ? "PrivateIdentifier" : "IdentifierName", value: match[0] }); continue; } StringLiteral.lastIndex = lastIndex; if (match = StringLiteral.exec(input)) { lastIndex = StringLiteral.lastIndex; lastSignificantToken = match[0]; postfixIncDec = true; yield ({ type: "StringLiteral", value: match[0], closed: match[2] !== void 0 }); continue; } NumericLiteral.lastIndex = lastIndex; if (match = NumericLiteral.exec(input)) { lastIndex = NumericLiteral.lastIndex; lastSignificantToken = match[0]; postfixIncDec = true; yield ({ type: "NumericLiteral", value: match[0] }); continue; } Template.lastIndex = lastIndex; if (match = Template.exec(input)) { lastIndex = Template.lastIndex; lastSignificantToken = match[0]; if (match[1] === "${") { lastSignificantToken = "?InterpolationInTemplate"; stack.push({ tag: "InterpolationInTemplate", nesting: braces.length }); postfixIncDec = false; yield ({ type: "TemplateHead", value: match[0] }); } else { postfixIncDec = true; yield ({ type: "NoSubstitutionTemplate", value: match[0], closed: match[1] === "`" }); } continue; } break; case "JSXTag": case "JSXTagEnd": JSXPunctuator.lastIndex = lastIndex; if (match = JSXPunctuator.exec(input)) { lastIndex = JSXPunctuator.lastIndex; nextLastSignificantToken = match[0]; switch (match[0]) { case "<": stack.push({tag: "JSXTag"}); break; case ">": stack.pop(); if (lastSignificantToken === "/" || mode.tag === "JSXTagEnd") { nextLastSignificantToken = "?JSX"; postfixIncDec = true; } else { stack.push({tag: "JSXChildren"}); } break; case "{": stack.push({ tag: "InterpolationInJSX", nesting: braces.length }); nextLastSignificantToken = "?InterpolationInJSX"; postfixIncDec = false; break; case "/": if (lastSignificantToken === "<") { stack.pop(); if (stack[stack.length - 1].tag === "JSXChildren") { stack.pop(); } stack.push({tag: "JSXTagEnd"}); } } lastSignificantToken = nextLastSignificantToken; yield ({ type: "JSXPunctuator", value: match[0] }); continue; } JSXIdentifier.lastIndex = lastIndex; if (match = JSXIdentifier.exec(input)) { lastIndex = JSXIdentifier.lastIndex; lastSignificantToken = match[0]; yield ({ type: "JSXIdentifier", value: match[0] }); continue; } JSXString.lastIndex = lastIndex; if (match = JSXString.exec(input)) { lastIndex = JSXString.lastIndex; lastSignificantToken = match[0]; yield ({ type: "JSXString", value: match[0], closed: match[2] !== void 0 }); continue; } break; case "JSXChildren": JSXText.lastIndex = lastIndex; if (match = JSXText.exec(input)) { lastIndex = JSXText.lastIndex; lastSignificantToken = match[0]; yield ({ type: "JSXText", value: match[0] }); continue; } switch (input[lastIndex]) { case "<": stack.push({tag: "JSXTag"}); lastIndex++; lastSignificantToken = "<"; yield ({ type: "JSXPunctuator", value: "<" }); continue; case "{": stack.push({ tag: "InterpolationInJSX", nesting: braces.length }); lastIndex++; lastSignificantToken = "?InterpolationInJSX"; postfixIncDec = false; yield ({ type: "JSXPunctuator", value: "{" }); continue; } } WhiteSpace.lastIndex = lastIndex; if (match = WhiteSpace.exec(input)) { lastIndex = WhiteSpace.lastIndex; yield ({ type: "WhiteSpace", value: match[0] }); continue; } LineTerminatorSequence.lastIndex = lastIndex; if (match = LineTerminatorSequence.exec(input)) { lastIndex = LineTerminatorSequence.lastIndex; postfixIncDec = false; if (KeywordsWithNoLineTerminatorAfter.test(lastSignificantToken)) { lastSignificantToken = "?NoLineTerminatorHere"; } yield ({ type: "LineTerminatorSequence", value: match[0] }); continue; } MultiLineComment.lastIndex = lastIndex; if (match = MultiLineComment.exec(input)) { lastIndex = MultiLineComment.lastIndex; if (Newline.test(match[0])) { postfixIncDec = false; if (KeywordsWithNoLineTerminatorAfter.test(lastSignificantToken)) { lastSignificantToken = "?NoLineTerminatorHere"; } } yield ({ type: "MultiLineComment", value: match[0], closed: match[1] !== void 0 }); continue; } SingleLineComment.lastIndex = lastIndex; if (match = SingleLineComment.exec(input)) { lastIndex = SingleLineComment.lastIndex; postfixIncDec = false; yield ({ type: "SingleLineComment", value: match[0] }); continue; } firstCodePoint = String.fromCodePoint(input.codePointAt(lastIndex)); lastIndex += firstCodePoint.length; lastSignificantToken = firstCodePoint; postfixIncDec = false; yield ({ type: mode.tag.startsWith("JSX") ? "JSXInvalid" : "Invalid", value: firstCodePoint }); } return void 0; }; return jsTokens_1; } var jsTokensExports = requireJsTokens(); var jsTokens = /*@__PURE__*/getDefaultExportFromCjs(jsTokensExports); function stripLiteralJsTokens(code, options) { const FILL = " "; const FILL_COMMENT = " "; let result = ""; const tokens = []; for (const token of jsTokens(code, { jsx: false })) { tokens.push(token); if (token.type === "SingleLineComment") { result += FILL_COMMENT.repeat(token.value.length); continue; } if (token.type === "MultiLineComment") { result += token.value.replace(/[^\n]/g, FILL_COMMENT); continue; } if (token.type === "StringLiteral") { if (!token.closed) { result += token.value; continue; } const body = token.value.slice(1, -1); { result += token.value[0] + FILL.repeat(body.length) + token.value[token.value.length - 1]; continue; } } if (token.type === "NoSubstitutionTemplate") { const body = token.value.slice(1, -1); { result += `\`${body.replace(/[^\n]/g, FILL)}\``; continue; } } if (token.type === "RegularExpressionLiteral") { const body = token.value; { result += body.replace(/\/(.*)\/(\w?)$/g, (_, $1, $2) => `/${FILL.repeat($1.length)}/${$2}`); continue; } } if (token.type === "TemplateHead") { const body = token.value.slice(1, -2); { result += `\`${body.replace(/[^\n]/g, FILL)}\${`; continue; } } if (token.type === "TemplateTail") { const body = token.value.slice(0, -2); { result += `}${body.replace(/[^\n]/g, FILL)}\``; continue; } } if (token.type === "TemplateMiddle") { const body = token.value.slice(1, -2); { result += `}${body.replace(/[^\n]/g, FILL)}\${`; continue; } } result += token.value; } return { result, tokens }; } function stripLiteral(code, options) { return stripLiteralDetailed(code).result; } function stripLiteralDetailed(code, options) { return stripLiteralJsTokens(code); } const metaUrlLength = "import.meta.url".length; const locationString = "self.location".padEnd(metaUrlLength, " "); function NormalizeURLPlugin() { return { name: "vitest:normalize-url", enforce: "post", transform(code, id, options) { const ssr = options?.ssr === true; if (ssr || !code.includes("new URL") || !code.includes("import.meta.url")) { return; } const cleanString = stripLiteral(code); const assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*(?:'[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*(?:,\s*)?\)/g; let updatedCode = code; let match; while (match = assetImportMetaUrlRE.exec(cleanString)) { const { 0: exp, index } = match; const metaUrlIndex = index + exp.indexOf("import.meta.url"); updatedCode = updatedCode.slice(0, metaUrlIndex) + locationString + updatedCode.slice(metaUrlIndex + metaUrlLength); } return { code: updatedCode, map: null }; } }; } function resolveOptimizerConfig(_testOptions, viteOptions, testConfig) { const testOptions = _testOptions || {}; const newConfig = {}; const [major, minor, fix] = version.split(".").map(Number); const allowed = major >= 5 || major === 4 && minor >= 4 || major === 4 && minor === 3 && fix >= 2; if (!allowed && testOptions?.enabled === true) { console.warn( `Vitest: "deps.optimizer" is only available in Vite >= 4.3.2, current Vite version: ${version}` ); } else { testOptions.enabled ??= false; } if (!allowed || testOptions?.enabled !== true) { newConfig.cacheDir = void 0; newConfig.optimizeDeps = { // experimental in Vite >2.9.2, entries remains to help with older versions disabled: true, entries: [] }; } else { const root = testConfig.root ?? process.cwd(); const cacheDir = testConfig.cache !== false ? testConfig.cache?.dir : void 0; const currentInclude = testOptions.include || viteOptions?.include || []; const exclude = [ "vitest", // Ideally, we shouldn't optimize react in test mode, otherwise we need to optimize _every_ dependency that uses react. "react", "vue", ...testOptions.exclude || viteOptions?.exclude || [] ]; const runtime = currentInclude.filter( (n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime") ); exclude.push(...runtime); const include = (testOptions.include || viteOptions?.include || []).filter( (n) => !exclude.includes(n) ); newConfig.cacheDir = cacheDir ?? VitestCache.resolveCacheDir(root, cacheDir, testConfig.name); newConfig.optimizeDeps = { ...viteOptions, ...testOptions, noDiscovery: true, disabled: false, entries: [], exclude, include }; } if (major >= 5 && minor >= 1 || major >= 6) { if (newConfig.optimizeDeps.disabled) { newConfig.optimizeDeps.noDiscovery = true; newConfig.optimizeDeps.include = []; } delete newConfig.optimizeDeps.disabled; } return newConfig; } function deleteDefineConfig(viteConfig) { const defines = {}; if (viteConfig.define) { delete viteConfig.define["import.meta.vitest"]; delete viteConfig.define["process.env"]; delete viteConfig.define.process; delete viteConfig.define.global; } for (const key in viteConfig.define) { const val = viteConfig.define[key]; let replacement; try { replacement = typeof val === "string" ? JSON.parse(val) : val; } catch { continue; } if (key.startsWith("import.meta.env.")) { const envKey = key.slice("import.meta.env.".length); process.env[envKey] = replacement; delete viteConfig.define[key]; } else if (key.startsWith("process.env.")) { const envKey = key.slice("process.env.".length); process.env[envKey] = replacement; delete viteConfig.define[key]; } else if (!key.includes(".")) { defines[key] = replacement; delete viteConfig.define[key]; } } return defines; } function hijackVitePluginInject(viteConfig) { const processEnvPlugin = viteConfig.plugins.find( (p) => p.name === "vite:client-inject" ); if (processEnvPlugin) { const originalTransform = processEnvPlugin.transform; processEnvPlugin.transform = function transform(code, id, options) { return originalTransform.call(this, code, id, { ...options, ssr: true }); }; } } function resolveFsAllow(projectRoot, rootConfigFile) { if (!rootConfigFile) { return [searchForWorkspaceRoot(projectRoot), rootDir]; } return [ dirname(rootConfigFile), searchForWorkspaceRoot(projectRoot), rootDir ]; } function VitestOptimizer() { return { name: "vitest:normalize-optimizer", config: { order: "post", handler(viteConfig) { const testConfig = viteConfig.test || {}; const webOptimizer = resolveOptimizerConfig( testConfig.deps?.optimizer?.web, viteConfig.optimizeDeps, testConfig ); const ssrOptimizer = resolveOptimizerConfig( testConfig.deps?.optimizer?.ssr, viteConfig.ssr?.optimizeDeps, testConfig ); viteConfig.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || viteConfig.cacheDir; viteConfig.optimizeDeps = webOptimizer.optimizeDeps; viteConfig.ssr ??= {}; viteConfig.ssr.optimizeDeps = ssrOptimizer.optimizeDeps; } } }; } function SsrReplacerPlugin() { return { name: "vitest:ssr-replacer", enforce: "pre", transform(code, id) { if (!/\bimport\.meta\.env\b/.test(code)) { return null; } let s = null; const cleanCode = stripLiteral(code); const envs = cleanCode.matchAll(/\bimport\.meta\.env\b/g); for (const env of envs) { s ||= new MagicString(code); const startIndex = env.index; const endIndex = startIndex + env[0].length; s.overwrite(startIndex, endIndex, "__vite_ssr_import_meta__.env"); } if (s) { return { code: s.toString(), map: s.generateMap({ hires: "boundary", // Remove possible query parameters, e.g. vue's "?vue&type=script&src=true&lang.ts" source: cleanUrl(id) }) }; } } }; } function VitestProjectResolver(ctx) { const plugin = { name: "vitest:resolve-root", enforce: "pre", async resolveId(id, _, { ssr }) { if (id === "vitest" || id.startsWith("@vitest/") || id.startsWith("vitest/")) { const resolved = await ctx.server.pluginContainer.resolveId(id, void 0, { skip: /* @__PURE__ */ new Set([plugin]), ssr }); return resolved; } } }; return plugin; } function VitestCoreResolver(ctx) { return { name: "vitest:resolve-core", enforce: "pre", async resolveId(id) { if (id === "vitest") { return resolve(distDir, "index.js"); } if (id.startsWith("@vitest/") || id.startsWith("vitest/")) { return this.resolve(id, join(ctx.config.root, "index.html"), { skipSelf: true }); } } }; } function WorkspaceVitestPlugin(project, options) { return [ { name: "vitest:project", enforce: "pre", options() { this.meta.watchMode = false; }, config(viteConfig) { const defines = deleteDefineConfig(viteConfig); const testConfig = viteConfig.test || {}; const root = testConfig.root || viteConfig.root || options.root; let name = testConfig.name; if (!name) { if (typeof options.workspacePath === "string") { const dir = options.workspacePath.endsWith("/") ? options.workspacePath.slice(0, -1) : dirname(options.workspacePath); const pkgJsonPath = resolve(dir, "package.json"); if (existsSync(pkgJsonPath)) { name = JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name; } if (typeof name !== "string" || !name) { name = basename(dir); } } else { name = options.workspacePath.toString(); } } const config = { root, resolve: { // by default Vite resolves `module` field, which not always a native ESM module // setting this option can bypass that and fallback to cjs version mainFields: [], alias: testConfig.alias, conditions: ["node"] }, esbuild: viteConfig.esbuild === false ? false : { // Lowest target Vitest supports is Node18 target: viteConfig.esbuild?.target || "node18", sourcemap: "external", // Enables using ignore hint for coverage providers with @preserve keyword legalComments: "inline" }, server: { // disable watch mode in workspaces, // because it is handled by the top-level watcher watch: null, open: false, hmr: false, ws: false, preTransformRequests: false, middlewareMode: true, fs: { allow: resolveFsAllow( project.ctx.config.root, project.ctx.server.config.configFile ) } }, // eslint-disable-next-line ts/ban-ts-comment // @ts-ignore Vite 6 compat environments: { ssr: { resolve: { // by default Vite resolves `module` field, which not always a native ESM module // setting this option can bypass that and fallback to cjs version mainFields: [], conditions: ["node"] } } }, test: { name } }; config.test.defines = defines; const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable"; if (classNameStrategy !== "scoped") { config.css ??= {}; config.css.modules ??= {}; if (config.css.modules) { config.css.modules.generateScopedName = (name2, filename) => { const root2 = project.config.root; return generateScopedClassName( classNameStrategy, name2, relative(root2, filename) ); }; } } config.customLogger = createViteLogger( project.logger, viteConfig.logLevel || "warn", { allowClearScreen: false } ); config.customLogger = silenceImportViteIgnoreWarning(config.customLogger); return config; }, configResolved(viteConfig) { hijackVitePluginInject(viteConfig); }, async configureServer(server) { const options2 = deepMerge({}, configDefaults, server.config.test || {}); await project.setServer(options2, server); await server.watcher.close(); } }, SsrReplacerPlugin(), ...CSSEnablerPlugin(project), CoverageTransform(project.ctx), ...MocksPlugins(), VitestProjectResolver(project.ctx), VitestOptimizer(), NormalizeURLPlugin() ]; } class TestSpecification { /** * @deprecated use `project` instead */ 0; /** * @deprecated use `moduleId` instead */ 1; /** * @deprecated use `pool` instead */ 2; project; moduleId; pool; // public readonly location: WorkspaceSpecLocation | undefined constructor(workspaceProject, moduleId, pool) { this[0] = workspaceProject; this[1] = moduleId; this[2] = { pool }; this.project = workspaceProject.testProject; this.moduleId = moduleId; this.pool = pool; } toJSON() { return [ { name: this.project.config.name, root: this.project.config.root }, this.moduleId, { pool: this.pool } ]; } /** * for backwards compatibility * @deprecated */ *[Symbol.iterator]() { yield this.project.workspaceProject; yield this.moduleId; yield this.pool; } } async function createViteServer(inlineConfig) { const error = console.error; console.error = (...args) => { if (typeof args[0] === "string" && args[0].includes("WebSocket server error:")) { return; } error(...args); }; const server = await createServer(inlineConfig); console.error = error; return server; } async function initializeProject(workspacePath, ctx, options) { const project = new WorkspaceProject(workspacePath, ctx, options); const root = options.root || (typeof workspacePath === "number" ? void 0 : workspacePath.endsWith("/") ? workspacePath : dirname(workspacePath)); const configFile = options.extends ? resolve(dirname(options.workspaceConfigPath), options.extends) : typeof workspacePath === "number" || workspacePath.endsWith("/") ? false : workspacePath; const config = { ...options, root, configFile, // this will make "mode": "test" | "benchmark" inside defineConfig mode: options.test?.mode || options.mode || ctx.config.mode, plugins: [ ...options.plugins || [], WorkspaceVitestPlugin(project, { ...options, root, workspacePath }) ] }; await createViteServer(config); return project; } class WorkspaceProject { constructor(path2, ctx, options) { this.path = path2; this.ctx = ctx; this.options = options; } configOverride; config; server; vitenode; runner; browser; typechecker; closingPromise; testFilesList = null; typecheckFilesList = null; testProject; id = nanoid(); tmpDir = join(tmpdir(), this.id); _globalSetups; _provided = {}; getName() { return this.config.name || ""; } isCore() { return this.ctx.getCoreWorkspaceProject() === this; } provide(key, value) { try { structuredClone(value); } catch (err) { throw new Error( `Cannot provide "${key}" because it's not serializable.`, { cause: err } ); } this._provided[key] = value; } getProvidedContext() { if (this.isCore()) { return this._provided; } return { ...this.ctx.getCoreWorkspaceProject().getProvidedContext(), ...this._provided }; } createSpec(moduleId, pool) { return new TestSpecification(this, moduleId, pool); } async initializeGlobalSetup() { if (this._globalSetups) { return; } this._globalSetups = await loadGlobalSetupFiles( this.runner, this.config.globalSetup ); for (const globalSetupFile of this._globalSetups) { const teardown = await globalSetupFile.setup?.({ provide: (key, value) => this.provide(key, value), config: this.config }); if (teardown == null || !!globalSetupFile.teardown) { continue; } if (typeof teardown !== "function") { throw new TypeError( `invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function` ); } globalSetupFile.teardown = teardown; } } async teardownGlobalSetup() { if (!this._globalSetups) { return; } for (const globalSetupFile of [...this._globalSetups].reverse()) { await globalSetupFile.teardown?.(); } } get logger() { return this.ctx.logger; } // it's possible that file path was imported with different queries (?raw, ?url, etc) getModulesByFilepath(file) { const set = this.server.moduleGraph.getModulesByFile(file) || this.browser?.vite.moduleGraph.getModulesByFile(file); return set || /* @__PURE__ */ new Set(); } getModuleById(id) { return this.server.moduleGraph.getModuleById(id) || this.browser?.vite.moduleGraph.getModuleById(id); } getSourceMapModuleById(id) { const mod = this.server.moduleGraph.getModuleById(id); return mod?.ssrTransformResult?.map || mod?.transformResult?.map; } get reporters() { return this.ctx.reporters; } async globTestFiles(filters = []) { const dir = this.config.dir || this.config.root; const { include, exclude, includeSource } = this.config; const typecheck = this.config.typecheck; const [testFiles, typecheckTestFiles] = await Promise.all([ typecheck.enabled && typecheck.only ? [] : this.globAllTestFiles(include, exclude, includeSource, dir), typecheck.enabled ? this.typecheckFilesList || this.globFiles(typecheck.include, typecheck.exclude, dir) : [] ]); this.typecheckFilesList = typecheckTestFiles; return { testFiles: this.filterFiles( testFiles, filters, dir ), typecheckTestFiles: this.filterFiles( typecheckTestFiles, filters, dir ) }; } async globAllTestFiles(include, exclude, includeSource, cwd) { if (this.testFilesList) { return this.testFilesList; } const testFiles = await this.globFiles(include, exclude, cwd); if (includeSource?.length) { const files = await this.globFiles(includeSource, exclude, cwd); await Promise.all( files.map(async (file) => { try { const code = await promises.readFile(file, "utf-8"); if (this.isInSourceTestFile(code)) { testFiles.push(file); } } catch { return null; } }) ); } this.testFilesList = testFiles; return testFiles; } isTestFile(id) { return this.testFilesList && this.testFilesList.includes(id); } isTypecheckFile(id) { return this.typecheckFilesList && this.typecheckFilesList.includes(id); } async globFiles(include, exclude, cwd) { const globOptions = { dot: true, cwd, ignore: exclude }; const files = await fg(include, globOptions); return files.map((file) => slash(a.resolve(cwd, file))); } async isTargetFile(id, source) { const relativeId = relative(this.config.dir || this.config.root, id); if (mm.isMatch(relativeId, this.config.exclude)) { return false; } if (mm.isMatch(relativeId, this.config.include)) { return true; } if (this.config.includeSource?.length && mm.isMatch(relativeId, this.config.includeSource)) { source = source || await promises.readFile(id, "utf-8"); return this.isInSourceTestFile(source); } return false; } isInSourceTestFile(code) { return code.includes("import.meta.vitest"); } filterFiles(testFiles, filters, dir) { if (filters.length && process.platform === "win32") { filters = filters.map((f) => slash(f)); } if (filters.length) { return testFiles.filter((t) => { const testFile = relative(dir, t).toLocaleLowerCase(); return filters.some((f) => { if (isAbsolute(f) && t.startsWith(f)) { return true; } const relativePath = f.endsWith("/") ? join(relative(dir, f), "/") : relative(dir, f); return testFile.includes(f.toLocaleLowerCase()) || testFile.includes(relativePath.toLocaleLowerCase()); }); }); } return testFiles; } async initBrowserServer() { if (!this.isBrowserEnabled() || this.browser) { return; } await this.ctx.packageInstaller.ensureInstalled("@vitest/browser", this.config.root, this.ctx.version); const { createBrowserServer, distRoot } = await import('@vitest/browser'); const browser = await createBrowserServer( this, this.server.config.configFile, [ ...MocksPlugins({ filter(id) { if (id.includes(distRoot)) { return false; } return true; } }) ], [CoverageTransform(this.ctx)] ); this.browser = browser; if (this.config.browser.ui) { setup(this.ctx, browser.vite); } } static createBasicProject(ctx) { const project = new WorkspaceProject( ctx.config.name || ctx.config.root, ctx ); project.vitenode = ctx.vitenode; project.server = ctx.server; project.runner = ctx.runner; project.config = ctx.config; for (const _providedKey in ctx.config.provide) { const providedKey = _providedKey; project.provide( providedKey, ctx.config.provide[providedKey] ); } project.testProject = new TestProject(project); return project; } static async createCoreProject(ctx) { return WorkspaceProject.createBasicProject(ctx); } async setServer(options, server) { this.config = resolveConfig( this.ctx.mode, { ...options, coverage: this.ctx.config.coverage }, server.config, this.ctx.logger ); for (const _providedKey in this.config.provide) { const providedKey = _providedKey; this.provide( providedKey, this.config.provide[providedKey] ); } this.closingPromise = void 0; this.testProject = new TestProject(this); this.server = server; this.vitenode = new ViteNodeServer(server, this.config.server); const node = this.vitenode; this.runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, fetchModule(id) { return node.fetchModule(id); }, resolveId(id, importer) { return node.resolveId(id, importer); } }); } isBrowserEnabled() { return isBrowserEnabled(this.config); } getSerializableConfig() { const config = serializeConfig( this.config, this.ctx.config, this.server.config ); if (!this.ctx.configOverride) { return config; } return deepMerge( config, this.ctx.configOverride ); } close() { if (!this.closingPromise) { this.closingPromise = Promise.all( [ this.server?.close(), this.typechecker?.stop(), this.browser?.close(), this.clearTmpDir() ].filter(Boolean) ).then(() => this._provided = {}); } return this.closingPromise; } async clearTmpDir() { try { await rm(this.tmpDir, { recursive: true }); } catch { } } async initBrowserProvider() { if (!this.isBrowserEnabled() || this.browser?.provider) { return; } if (!this.browser) { await this.initBrowserServer(); } await this.browser?.initBrowserProvider(); } } const ESCAPE_SYMBOL = "\\"; const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; const REGEX_CHARACTER_CLASS_SYMBOLS_RE = /\[[^[]*\]/; const REGEX_GROUP_SYMBOLS_RE = /(?:^|[^!*+?@])\([^(]*\|[^|]*\)/; const GLOB_EXTENSION_SYMBOLS_RE = /[!*+?@]\([^(]*\)/; const BRACE_EXPANSION_SEPARATORS_RE = /,|\.\./; function isDynamicPattern(pattern, options = {}) { if (pattern === "") { return false; } if (options.caseSensitiveMatch === false || pattern.includes(ESCAPE_SYMBOL)) { return true; } if (COMMON_GLOB_SYMBOLS_RE.test(pattern) || REGEX_CHARACTER_CLASS_SYMBOLS_RE.test(pattern) || REGEX_GROUP_SYMBOLS_RE.test(pattern)) { return true; } if (options.extglob !== false && GLOB_EXTENSION_SYMBOLS_RE.test(pattern)) { return true; } if (options.braceExpansion !== false && hasBraceExpansion(pattern)) { return true; } return false; } function hasBraceExpansion(pattern) { const openingBraceIndex = pattern.indexOf("{"); if (openingBraceIndex === -1) { return false; } const closingBraceIndex = pattern.indexOf("}", openingBraceIndex + 1); if (closingBraceIndex === -1) { return false; } const braceContent = pattern.slice(openingBraceIndex, closingBraceIndex); return BRACE_EXPANSION_SEPARATORS_RE.test(braceContent); } async function resolveWorkspace(vitest, cliOptions, workspaceConfigPath, workspaceDefinition) { const { configFiles, projectConfigs, nonConfigDirectories } = await resolveWorkspaceProjectConfigs( vitest, workspaceConfigPath, workspaceDefinition ); const overridesOptions = [ "logHeapUsage", "allowOnly", "sequence", "testTimeout", "pool", "update", "globals", "expandSnapshotDiff", "disableConsoleIntercept", "retry", "testNamePattern", "passWithNoTests", "bail", "isolate", "printConsoleTrace" ]; const cliOverrides = overridesOptions.reduce((acc, name) => { if (name in cliOptions) { acc[name] = cliOptions[name]; } return acc; }, {}); const projectPromises = []; const fileProjects = [...configFiles, ...nonConfigDirectories]; const concurrent = limitConcurrency(nodeos__default.availableParallelism?.() || nodeos__default.cpus().length || 5); for (const filepath of fileProjects) { if (vitest.server.config.configFile === filepath) { projectPromises.push(concurrent(() => vitest._createCoreProject())); continue; } projectPromises.push( concurrent(() => initializeProject( filepath, vitest, { workspaceConfigPath, test: cliOverrides } )) ); } projectConfigs.forEach((options, index) => { projectPromises.push(concurrent(() => initializeProject( index, vitest, mergeConfig(options, { workspaceConfigPath, test: cliOverrides }) ))); }); if (!projectPromises.length) { return [await vitest._createCoreProject()]; } const resolvedProjects = await Promise.all(projectPromises); const names = /* @__PURE__ */ new Set(); for (const project of resolvedProjects) { const name = project.getName(); if (names.has(name)) { const duplicate = resolvedProjects.find((p) => p.getName() === name && p !== project); const filesError = fileProjects.length ? [ "\n\nYour config matched these files:\n", fileProjects.map((p) => ` - ${relative(vitest.config.root, p)}`).join("\n"), "\n\n" ].join("") : [" "]; throw new Error([ `Project name "${name}"`, project.server.config.configFile ? ` from "${relative(vitest.config.root, project.server.config.configFile)}"` : "", " is not unique.", duplicate?.server.config.configFile ? ` The project is already defined by "${relative(vitest.config.root, duplicate.server.config.configFile)}".` : "", filesError, "All projects in a workspace should have unique names. Make sure your configuration is correct." ].join("")); } names.add(name); } return resolvedProjects; } async function resolveWorkspaceProjectConfigs(vitest, workspaceConfigPath, workspaceDefinition) { const projectsOptions = []; const workspaceConfigFiles = []; const workspaceGlobMatches = []; const nonConfigProjectDirectories = []; const relativeWorkpaceConfigPath = relative(vitest.config.root, workspaceConfigPath); for (const definition of workspaceDefinition) { if (typeof definition === "string") { const stringOption = definition.replace("", vitest.config.root); if (!isDynamicPattern(stringOption)) { const file = resolve(vitest.config.root, stringOption); if (!existsSync(file)) { throw new Error(`Workspace config file "${relativeWorkpaceConfigPath}" references a non-existing file or a directory: ${file}`); } const stats = await promises.stat(file); if (stats.isFile()) { workspaceConfigFiles.push(file); } else if (stats.isDirectory()) { const configFile = await resolveDirectoryConfig(file); if (configFile) { workspaceConfigFiles.push(configFile); } else { const directory = file[file.length - 1] === "/" ? file : `${file}/`; nonConfigProjectDirectories.push(directory); } } else { throw new TypeError(`Unexpected file type: ${file}`); } } else { workspaceGlobMatches.push(stringOption); } } else if (typeof definition === "function") { projectsOptions.push(await definition({ command: vitest.server.config.command, mode: vitest.server.config.mode, isPreview: false, isSsrBuild: false })); } else { projectsOptions.push(await definition); } } if (workspaceGlobMatches.length) { const globOptions = { absolute: true, dot: true, onlyFiles: false, cwd: vitest.config.root, markDirectories: true, // TODO: revert option when we go back to tinyglobby // expandDirectories: false, ignore: [ "**/node_modules/**", // temporary vite config file "**/*.timestamp-*", // macOS directory metadata "**/.DS_Store" ] }; const workspacesFs = await fg.glob(workspaceGlobMatches, globOptions); await Promise.all(workspacesFs.map(async (filepath) => { if (filepath.endsWith("/")) { const configFile = await resolveDirectoryConfig(filepath); if (configFile) { workspaceConfigFiles.push(configFile); } else { nonConfigProjectDirectories.push(filepath); } } else { workspaceConfigFiles.push(filepath); } })); } const projectConfigFiles = Array.from(new Set(workspaceConfigFiles)); return { projectConfigs: projectsOptions, nonConfigDirectories: nonConfigProjectDirectories, configFiles: projectConfigFiles }; } async function resolveDirectoryConfig(directory) { const files = new Set(await promises.readdir(directory)); const configFile = configFiles.find((file) => files.has(file)); if (configFile) { return resolve(directory, configFile); } return null; } const WATCHER_DEBOUNCE = 100; class Vitest { constructor(mode, options = {}) { this.mode = mode; this.logger = new Logger(this, options.stdout, options.stderr); this.packageInstaller = options.packageInstaller || new VitestPackageInstaller(); } version = version$1; config = void 0; configOverride = {}; server = void 0; state = void 0; snapshot = void 0; cache = void 0; reporters = void 0; coverageProvider; logger; pool; vitenode = void 0; invalidates = /* @__PURE__ */ new Set(); changedTests = /* @__PURE__ */ new Set(); watchedTests = /* @__PURE__ */ new Set(); filenamePattern; runningPromise; closingPromise; isCancelling = false; isFirstRun = true; restartsCount = 0; runner = void 0; packageInstaller; coreWorkspaceProject; /** @private */ resolvedProjects = []; projects = []; distPath = distDir; _cachedSpecs = /* @__PURE__ */ new Map(); _workspaceConfigPath; /** @deprecated use `_cachedSpecs` */ projectTestFiles = this._cachedSpecs; /** @private */ _browserLastPort = defaultBrowserPort; _onRestartListeners = []; _onClose = []; _onSetServer = []; _onCancelListeners = []; async setServer(options, server, cliOptions) { this.unregisterWatcher?.(); clearTimeout(this._rerunTimer); this.restartsCount += 1; this._browserLastPort = defaultBrowserPort; this.pool?.close?.(); this.pool = void 0; this.closingPromise = void 0; this.projects = []; this.resolvedProjects = []; this._workspaceConfigPath = void 0; this.coverageProvider = void 0; this.runningPromise = void 0; this._cachedSpecs.clear(); const resolved = resolveConfig(this.mode, options, server.config, this.logger); this.server = server; this.config = resolved; this.state = new StateManager(); this.cache = new VitestCache(this.version); this.snapshot = new SnapshotManager({ ...resolved.snapshotOptions }); if (this.config.watch) { this.registerWatcher(); } this.vitenode = new ViteNodeServer(server, this.config.server); const node = this.vitenode; this.runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, fetchModule(id) { return node.fetchModule(id); }, resolveId(id, importer) { return node.resolveId(id, importer); } }); if (this.config.watch) { const serverRestart = server.restart; server.restart = async (...args) => { await Promise.all(this._onRestartListeners.map((fn) => fn())); this.report("onServerRestart"); await this.close(); await serverRestart(...args); }; server.watcher.on("change", async (file) => { file = normalize(file); const isConfig = file === server.config.configFile || this.resolvedProjects.some((p) => p.server.config.configFile === file) || file === this._workspaceConfigPath; if (isConfig) { await Promise.all(this._onRestartListeners.map((fn) => fn("config"))); this.report("onServerRestart", "config"); await this.close(); await serverRestart(); } }); } this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray(resolved.benchmark?.reporters), this.runner) : await createReporters(resolved.reporters, this); this.cache.results.setConfig(resolved.root, resolved.cache); try { await this.cache.results.readFromCache(); } catch { } const projects = await this.resolveWorkspace(cliOptions); this.resolvedProjects = projects; this.projects = projects; const filters = toArray(resolved.project).map((s) => wildcardPatternToRegExp(s)); if (filters.length > 0) { this.projects = this.projects.filter( (p) => filters.some((pattern) => pattern.test(p.getName())) ); } if (!this.coreWorkspaceProject) { this.coreWorkspaceProject = WorkspaceProject.createBasicProject(this); } if (this.config.testNamePattern) { this.configOverride.testNamePattern = this.config.testNamePattern; } await Promise.all(this._onSetServer.map((fn) => fn())); } provide(key, value) { this.getCoreWorkspaceProject().provide(key, value); } /** * @deprecated internal, use `_createCoreProject` instead */ createCoreProject() { return this._createCoreProject(); } /** * @internal */ async _createCoreProject() { this.coreWorkspaceProject = await WorkspaceProject.createCoreProject(this); return this.coreWorkspaceProject; } getCoreWorkspaceProject() { return this.coreWorkspaceProject; } /** * @deprecated use Reported Task API instead */ getProjectByTaskId(taskId) { const task = this.state.idMap.get(taskId); const projectName = task.projectName || task?.file?.projectName || ""; return this.projects.find((p) => p.getName() === projectName) || this.getCoreWorkspaceProject() || this.projects[0]; } getProjectByName(name = "") { return this.projects.find((p) => p.getName() === name) || this.getCoreWorkspaceProject() || this.projects[0]; } async getWorkspaceConfigPath() { if (this.config.workspace) { return this.config.workspace; } const configDir = this.server.config.configFile ? dirname(this.server.config.configFile) : this.config.root; const rootFiles = await promises.readdir(configDir); const workspaceConfigName = workspacesFiles.find((configFile) => { return rootFiles.includes(configFile); }); if (!workspaceConfigName) { return void 0; } return join(configDir, workspaceConfigName); } async resolveWorkspace(cliOptions) { const workspaceConfigPath = await this.getWorkspaceConfigPath(); this._workspaceConfigPath = workspaceConfigPath; if (!workspaceConfigPath) { return [await this._createCoreProject()]; } const workspaceModule = await this.runner.executeFile(workspaceConfigPath); if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) { throw new TypeError(`Workspace config file "${workspaceConfigPath}" must export a default array of project paths.`); } return resolveWorkspace( this, cliOptions, workspaceConfigPath, workspaceModule.default ); } async initCoverageProvider() { if (this.coverageProvider !== void 0) { return; } this.coverageProvider = await getCoverageProvider( this.config.coverage, this.runner ); if (this.coverageProvider) { await this.coverageProvider.initialize(this); this.config.coverage = this.coverageProvider.resolveOptions(); } return this.coverageProvider; } async mergeReports() { if (this.reporters.some((r) => r instanceof BlobReporter)) { throw new Error("Cannot merge reports when `--reporter=blob` is used. Remove blob reporter from the config first."); } const { files, errors, coverages } = await readBlobs(this.version, this.config.mergeReports, this.projects); await this.report("onInit", this); await this.report("onPathsCollected", files.flatMap((f) => f.filepath)); const workspaceSpecs = /* @__PURE__ */ new Map(); for (const file of files) { const project = this.getProjectByName(file.projectName); const specs = workspaceSpecs.get(project) || []; specs.push(file); workspaceSpecs.set(project, specs); } for (const [project, files2] of workspaceSpecs) { const filepaths = files2.map((f) => f.filepath); this.state.clearFiles(project, filepaths); files2.forEach((file) => { file.logs?.forEach((log) => this.state.updateUserLog(log)); }); this.state.collectFiles(project, files2); } await this.report("onCollected", files).catch(noop); for (const file of files) { const logs = []; const taskPacks = []; const tasks = getTasks(file); for (const task of tasks) { if (task.logs) { logs.push(...task.logs); } taskPacks.push([task.id, task.result, task.meta]); } logs.sort((log1, log2) => log1.time - log2.time); for (const log of logs) { await this.report("onUserConsoleLog", log).catch(noop); } await this.report("onTaskUpdate", taskPacks).catch(noop); } if (hasFailed(files)) { process.exitCode = 1; } this.checkUnhandledErrors(errors); await this.report("onFinished", files, errors); await this.initCoverageProvider(); await this.coverageProvider?.mergeReports?.(coverages); } async collect(filters) { this._onClose = []; const files = await this.filterTestsBySource( await this.globTestFiles(filters) ); if (!files.length) { return { tests: [], errors: [] }; } await this.collectFiles(files); return { tests: this.state.getFiles(), errors: this.state.getUnhandledErrors() }; } async listFiles(filters) { const files = await this.filterTestsBySource( await this.globTestFiles(filters) ); return files; } async start(filters) { this._onClose = []; try { await this.initCoverageProvider(); await this.coverageProvider?.clean(this.config.coverage.clean); } finally { await this.report("onInit", this); } const files = await this.filterTestsBySource( await this.globTestFiles(filters) ); if (!files.length) { const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true }); await this.reportCoverage(coverage, true); this.logger.printNoTestFound(filters); if (!this.config.watch || !(this.config.changed || this.config.related?.length)) { const exitCode = this.config.passWithNoTests ? 0 : 1; process.exitCode = exitCode; throw new FilesNotFoundError(this.mode); } } if (files.length) { await this.cache.stats.populateStats(this.config.root, files); await this.runFiles(files, true); } if (this.config.watch) { await this.report("onWatcherStart"); } } async init() { this._onClose = []; try { await this.initCoverageProvider(); await this.coverageProvider?.clean(this.config.coverage.clean); } finally { await this.report("onInit", this); } await this.globTestFiles(); if (this.config.watch) { await this.report("onWatcherStart"); } } async getTestDependencies(spec, deps = /* @__PURE__ */ new Set()) { const addImports = async (project, filepath) => { if (deps.has(filepath)) { return; } deps.add(filepath); const mod = project.server.moduleGraph.getModuleById(filepath); const transformed = mod?.ssrTransformResult || await project.vitenode.transformRequest(filepath); if (!transformed) { return; } const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []]; await Promise.all(dependencies.map(async (dep) => { const path = await project.server.pluginContainer.resolveId(dep, filepath, { ssr: true }); const fsPath = path && !path.external && path.id.split("?")[0]; if (fsPath && !fsPath.includes("node_modules") && !deps.has(fsPath) && existsSync(fsPath)) { await addImports(project, fsPath); } })); }; await addImports(spec.project.workspaceProject, spec.moduleId); deps.delete(spec.moduleId); return deps; } async filterTestsBySource(specs) { if (this.config.changed && !this.config.related) { const { VitestGit } = await import('./git.B5SDxu-n.js'); const vitestGit = new VitestGit(this.config.root); const related2 = await vitestGit.findChangedFiles({ changedSince: this.config.changed }); if (!related2) { process.exitCode = 1; throw new GitNotFoundError(); } this.config.related = Array.from(new Set(related2)); } const related = this.config.related; if (!related) { return specs; } const forceRerunTriggers = this.config.forceRerunTriggers; if (forceRerunTriggers.length && mm(related, forceRerunTriggers).length) { return specs; } if (!this.config.watch && !related.length) { return []; } const testGraphs = await Promise.all( specs.map(async (spec) => { const deps = await this.getTestDependencies(spec); return [spec, deps]; }) ); const runningTests = []; for (const [filepath, deps] of testGraphs) { if (related.some((path) => path === filepath[1] || deps.has(path))) { runningTests.push(filepath); } } return runningTests; } /** * @deprecated remove when vscode extension supports "getFileWorkspaceSpecs" */ getProjectsByTestFile(file) { return this.getFileWorkspaceSpecs(file); } getFileWorkspaceSpecs(file) { const _cached = this._cachedSpecs.get(file); if (_cached) { return _cached; } const specs = []; for (const project of this.projects) { if (project.isTestFile(file)) { const pool = getFilePoolName(project, file); specs.push(project.createSpec(file, pool)); } if (project.isTypecheckFile(file)) { specs.push(project.createSpec(file, "typescript")); } } specs.forEach((spec) => this.ensureSpecCached(spec)); return specs; } async initializeGlobalSetup(paths) { const projects = new Set(paths.map((spec) => spec.project.workspaceProject)); const coreProject = this.getCoreWorkspaceProject(); if (!projects.has(coreProject)) { projects.add(coreProject); } for (const project of projects) { await project.initializeGlobalSetup(); } } async runFiles(specs, allTestsRun) { const filepaths = specs.map((spec) => spec.moduleId); this.state.collectPaths(filepaths); await this.report("onPathsCollected", filepaths); await this.report("onSpecsCollected", specs.map((spec) => spec.toJSON())); await this.runningPromise; this._onCancelListeners = []; this.isCancelling = false; this.runningPromise = (async () => { if (!this.pool) { this.pool = createPool(this); } const invalidates = Array.from(this.invalidates); this.invalidates.clear(); this.snapshot.clear(); this.state.clearErrors(); if (!this.isFirstRun && this.config.coverage.cleanOnRerun) { await this.coverageProvider?.clean(); } await this.initializeGlobalSetup(specs); try { await this.pool.runTests(specs, invalidates); } catch (err) { this.state.catchError(err, "Unhandled Error"); } const files = this.state.getFiles(); if (hasFailed(files)) { process.exitCode = 1; } this.cache.results.updateResults(files); await this.cache.results.writeToCache(); })().finally(async () => { const files = Array.from(new Set(specs.map((spec) => spec.moduleId))); const errors = this.state.getUnhandledErrors(); const coverage = await this.coverageProvider?.generateCoverage({ allTestsRun }); this.checkUnhandledErrors(errors); await this.report("onFinished", this.state.getFiles(files), errors, coverage); await this.reportCoverage(coverage, allTestsRun); this.runningPromise = void 0; this.isFirstRun = false; this.config.changed = false; this.config.related = void 0; }); return await this.runningPromise; } async collectFiles(specs) { const filepaths = specs.map((spec) => spec.moduleId); this.state.collectPaths(filepaths); await this.runningPromise; this._onCancelListeners = []; this.isCancelling = false; this.runningPromise = (async () => { if (!this.pool) { this.pool = createPool(this); } const invalidates = Array.from(this.invalidates); this.invalidates.clear(); this.snapshot.clear(); this.state.clearErrors(); await this.initializeGlobalSetup(specs); try { await this.pool.collectTests(specs, invalidates); } catch (err) { this.state.catchError(err, "Unhandled Error"); } const files = this.state.getFiles(); if (hasFailed(files)) { process.exitCode = 1; } })().finally(async () => { this.runningPromise = void 0; this.config.changed = false; this.config.related = void 0; }); return await this.runningPromise; } async cancelCurrentRun(reason) { this.isCancelling = true; await Promise.all(this._onCancelListeners.splice(0).map((listener) => listener(reason))); } async initBrowserServers() { await Promise.all(this.projects.map((p) => p.initBrowserServer())); } async rerunFiles(files = this.state.getFilepaths(), trigger, allTestsRun = true) { if (this.filenamePattern) { const filteredFiles = await this.globTestFiles([this.filenamePattern]); files = files.filter((file) => filteredFiles.some((f) => f[1] === file)); } await this.report("onWatcherRerun", files, trigger); await this.runFiles(files.flatMap((file) => this.getProjectsByTestFile(file)), allTestsRun); await this.report("onWatcherStart", this.state.getFiles(files)); } async changeProjectName(pattern) { if (pattern === "") { delete this.configOverride.project; } else { this.configOverride.project = pattern; } this.projects = this.resolvedProjects.filter((p) => p.getName() === pattern); const files = (await this.globTestSpecs()).map((spec) => spec.moduleId); await this.rerunFiles(files, "change project filter", pattern === ""); } async changeNamePattern(pattern, files = this.state.getFilepaths(), trigger) { if (pattern === "") { this.filenamePattern = void 0; } const testNamePattern = pattern ? new RegExp(pattern) : void 0; this.configOverride.testNamePattern = testNamePattern; if (testNamePattern) { files = files.filter((filepath) => { const files2 = this.state.getFiles([filepath]); return !files2.length || files2.some((file) => { const tasks = getTasks(file); return !tasks.length || tasks.some((task) => testNamePattern.test(task.name)); }); }); } await this.rerunFiles(files, trigger, pattern === ""); } async changeFilenamePattern(pattern, files = this.state.getFilepaths()) { this.filenamePattern = pattern; const trigger = this.filenamePattern ? "change filename pattern" : "reset filename pattern"; await this.rerunFiles(files, trigger, pattern === ""); } async rerunFailed() { await this.rerunFiles(this.state.getFailedFilepaths(), "rerun failed", false); } async updateSnapshot(files) { files = files || [ ...this.state.getFailedFilepaths(), ...this.snapshot.summary.uncheckedKeysByFile.map((s) => s.filePath) ]; this.configOverride.snapshotOptions = { updateSnapshot: "all", // environment is resolved inside a worker thread snapshotEnvironment: null }; try { await this.rerunFiles(files, "update snapshot", false); } finally { delete this.configOverride.snapshotOptions; } } _rerunTimer; async scheduleRerun(triggerId) { const currentCount = this.restartsCount; clearTimeout(this._rerunTimer); await this.runningPromise; clearTimeout(this._rerunTimer); if (this.restartsCount !== currentCount) { return; } this._rerunTimer = setTimeout(async () => { if (this.watchedTests.size) { this.changedTests.forEach((test) => { if (!this.watchedTests.has(test)) { this.changedTests.delete(test); } }); } if (this.changedTests.size === 0) { this.invalidates.clear(); return; } if (this.restartsCount !== currentCount) { return; } this.isFirstRun = false; this.snapshot.clear(); let files = Array.from(this.changedTests); if (this.filenamePattern) { const filteredFiles = await this.globTestFiles([this.filenamePattern]); files = files.filter((file) => filteredFiles.some((f) => f[1] === file)); if (files.length === 0) { return; } } this.changedTests.clear(); const triggerIds = new Set(triggerId.map((id) => relative(this.config.root, id))); const triggerLabel = Array.from(triggerIds).join(", "); await this.report("onWatcherRerun", files, triggerLabel); await this.runFiles(files.flatMap((file) => this.getProjectsByTestFile(file)), false); await this.report("onWatcherStart", this.state.getFiles(files)); }, WATCHER_DEBOUNCE); } getModuleProjects(filepath) { return this.projects.filter((project) => { return project.getModulesByFilepath(filepath).size; }); } /** * Watch only the specified tests. If no tests are provided, all tests will be watched. */ watchTests(tests) { this.watchedTests = new Set( tests.map((test) => slash(test)) ); } updateLastChanged(filepath) { const projects = this.getModuleProjects(filepath); projects.forEach(({ server, browser }) => { const serverMods = server.moduleGraph.getModulesByFile(filepath); serverMods?.forEach((mod) => server.moduleGraph.invalidateModule(mod)); if (browser) { const browserMods = browser.vite.moduleGraph.getModulesByFile(filepath); browserMods?.forEach((mod) => browser.vite.moduleGraph.invalidateModule(mod)); } }); } onChange = (id) => { id = slash(id); this.logger.clearHighlightCache(id); this.updateLastChanged(id); const needsRerun = this.handleFileChanged(id); if (needsRerun.length) { this.scheduleRerun(needsRerun); } }; onUnlink = (id) => { id = slash(id); this.logger.clearHighlightCache(id); this.invalidates.add(id); if (this.state.filesMap.has(id)) { this.state.filesMap.delete(id); this.cache.results.removeFromCache(id); this.cache.stats.removeStats(id); this.changedTests.delete(id); this.report("onTestRemoved", id); } }; onAdd = async (id) => { id = slash(id); this.updateLastChanged(id); const matchingProjects = []; await Promise.all(this.projects.map(async (project) => { if (await project.isTargetFile(id)) { matchingProjects.push(project); project.testFilesList?.push(id); } })); if (matchingProjects.length > 0) { this.changedTests.add(id); this.scheduleRerun([id]); } else { const needsRerun = this.handleFileChanged(id); if (needsRerun.length) { this.scheduleRerun(needsRerun); } } }; checkUnhandledErrors(errors) { if (errors.length && !this.config.dangerouslyIgnoreUnhandledErrors) { process.exitCode = 1; } } unregisterWatcher = noop; registerWatcher() { const watcher = this.server.watcher; if (this.config.forceRerunTriggers.length) { watcher.add(this.config.forceRerunTriggers); } watcher.on("change", this.onChange); watcher.on("unlink", this.onUnlink); watcher.on("add", this.onAdd); this.unregisterWatcher = () => { watcher.off("change", this.onChange); watcher.off("unlink", this.onUnlink); watcher.off("add", this.onAdd); this.unregisterWatcher = noop; }; } /** * @returns A value indicating whether rerun is needed (changedTests was mutated) */ handleFileChanged(filepath) { if (this.changedTests.has(filepath) || this.invalidates.has(filepath)) { return []; } if (mm.isMatch(filepath, this.config.forceRerunTriggers)) { this.state.getFilepaths().forEach((file) => this.changedTests.add(file)); return [filepath]; } const projects = this.getModuleProjects(filepath); if (!projects.length) { if (this.state.filesMap.has(filepath) || this.projects.some((project) => project.isTestFile(filepath))) { this.changedTests.add(filepath); return [filepath]; } return []; } const files = []; for (const project of projects) { const mods = project.getModulesByFilepath(filepath); if (!mods.size) { continue; } this.invalidates.add(filepath); if (this.state.filesMap.has(filepath) || project.isTestFile(filepath)) { this.changedTests.add(filepath); files.push(filepath); continue; } let rerun = false; for (const mod of mods) { mod.importers.forEach((i) => { if (!i.file) { return; } const heedsRerun = this.handleFileChanged(i.file); if (heedsRerun.length) { rerun = true; } }); } if (rerun) { files.push(filepath); } } return Array.from(new Set(files)); } async reportCoverage(coverage, allTestsRun) { if (this.state.getCountOfFailedTests() > 0) { await this.coverageProvider?.onTestFailure?.(); if (!this.config.coverage.reportOnFailure) { return; } } if (this.coverageProvider) { await this.coverageProvider.reportCoverage(coverage, { allTestsRun }); for (const reporter of this.reporters) { if (reporter instanceof WebSocketReporter) { reporter.onFinishedReportCoverage(); } } } } async close() { if (!this.closingPromise) { this.closingPromise = (async () => { const teardownProjects = [...this.projects]; if (!teardownProjects.includes(this.coreWorkspaceProject)) { teardownProjects.push(this.coreWorkspaceProject); } for await (const project of teardownProjects.reverse()) { await project.teardownGlobalSetup(); } const closePromises = this.resolvedProjects.map((w) => w.close().then(() => w.server = void 0)); if (!this.resolvedProjects.includes(this.coreWorkspaceProject)) { closePromises.push(this.coreWorkspaceProject.close().then(() => this.server = void 0)); } if (this.pool) { closePromises.push((async () => { await this.pool?.close?.(); this.pool = void 0; })()); } closePromises.push(...this._onClose.map((fn) => fn())); return Promise.allSettled(closePromises).then((results) => { results.forEach((r) => { if (r.status === "rejected") { this.logger.error("error during close", r.reason); } }); this.logger.logUpdate.done(); }); })(); } return this.closingPromise; } /** * Close the thread pool and exit the process */ async exit(force = false) { setTimeout(() => { this.report("onProcessTimeout").then(() => { console.warn(`close timed out after ${this.config.teardownTimeout}ms`); this.state.getProcessTimeoutCauses().forEach((cause) => console.warn(cause)); if (!this.pool) { const runningServers = [this.server, ...this.resolvedProjects.map((p) => p.server)].filter(Boolean).length; if (runningServers === 1) { console.warn("Tests closed successfully but something prevents Vite server from exiting"); } else if (runningServers > 1) { console.warn(`Tests closed successfully but something prevents ${runningServers} Vite servers from exiting`); } else { console.warn("Tests closed successfully but something prevents the main process from exiting"); } console.warn('You can try to identify the cause by enabling "hanging-process" reporter. See https://vitest.dev/config/#reporters'); } process.exit(); }); }, this.config.teardownTimeout).unref(); await this.close(); if (force) { process.exit(); } } async report(name, ...args) { await Promise.all(this.reporters.map((r) => r[name]?.( ...args ))); } async getTestFilepaths() { return this.globTestSpecs().then((specs) => specs.map((spec) => spec.moduleId)); } async globTestSpecs(filters = []) { const files = []; await Promise.all(this.projects.map(async (project) => { const { testFiles, typecheckTestFiles } = await project.globTestFiles(filters); testFiles.forEach((file) => { const pool = getFilePoolName(project, file); const spec = project.createSpec(file, pool); this.ensureSpecCached(spec); files.push(spec); }); typecheckTestFiles.forEach((file) => { const spec = project.createSpec(file, "typescript"); this.ensureSpecCached(spec); files.push(spec); }); })); return files; } /** * @deprecated use globTestSpecs instead */ async globTestFiles(filters = []) { return this.globTestSpecs(filters); } ensureSpecCached(spec) { const file = spec[1]; const specs = this._cachedSpecs.get(file) || []; const included = specs.some((_s) => _s[0] === spec[0] && _s[2].pool === spec[2].pool); if (!included) { specs.push(spec); this._cachedSpecs.set(file, specs); } } // The server needs to be running for communication shouldKeepServer() { return !!this.config?.watch; } onServerRestart(fn) { this._onRestartListeners.push(fn); } onAfterSetServer(fn) { this._onSetServer.push(fn); } onCancel(fn) { this._onCancelListeners.push(fn); } onClose(fn) { this._onClose.push(fn); } } async function VitestPlugin(options = {}, ctx = new Vitest("test")) { const userConfig = deepMerge({}, options); const getRoot = () => ctx.config?.root || options.root || process.cwd(); async function UIPlugin() { await ctx.packageInstaller.ensureInstalled("@vitest/ui", getRoot(), ctx.version); return (await import('@vitest/ui')).default(ctx); } return [ { name: "vitest", enforce: "pre", options() { this.meta.watchMode = false; }, async config(viteConfig) { if (options.watch) { options = deepMerge({}, userConfig); } const testConfig = deepMerge( {}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options ); testConfig.api = resolveApiServerConfig(testConfig, defaultPort); const defines = deleteDefineConfig(viteConfig); options.defines = defines; let open = false; if (testConfig.ui && testConfig.open) { open = testConfig.uiBase ?? "/__vitest__/"; } const config = { root: viteConfig.test?.root || options.root, esbuild: viteConfig.esbuild === false ? false : { // Lowest target Vitest supports is Node18 target: viteConfig.esbuild?.target || "node18", sourcemap: "external", // Enables using ignore hint for coverage providers with @preserve keyword legalComments: "inline" }, resolve: { // by default Vite resolves `module` field, which not always a native ESM module // setting this option can bypass that and fallback to cjs version mainFields: [], alias: testConfig.alias, conditions: ["node"] }, server: { ...testConfig.api, open, hmr: false, ws: testConfig.api?.middlewareMode ? false : void 0, preTransformRequests: false, fs: { allow: resolveFsAllow(getRoot(), testConfig.config) } }, build: { // Vitest doesn't use outputDir, but this value affects what folders are watched // https://github.com/vitest-dev/vitest/issues/5429 // This works for Vite <5.2.10 outDir: "dummy-non-existing-folder", // This works for Vite >=5.2.10 // https://github.com/vitejs/vite/pull/16453 emptyOutDir: false }, // eslint-disable-next-line ts/ban-ts-comment // @ts-ignore Vite 6 compat environments: { ssr: { resolve: { // by default Vite resolves `module` field, which not always a native ESM module // setting this option can bypass that and fallback to cjs version mainFields: [], conditions: ["node"] } } }, test: { poolOptions: { threads: { isolate: options.poolOptions?.threads?.isolate ?? options.isolate ?? testConfig.poolOptions?.threads?.isolate ?? viteConfig.test?.isolate }, forks: { isolate: options.poolOptions?.forks?.isolate ?? options.isolate ?? testConfig.poolOptions?.forks?.isolate ?? viteConfig.test?.isolate } } } }; config.customLogger = createViteLogger( ctx.logger, viteConfig.logLevel || "warn", { allowClearScreen: false } ); config.customLogger = silenceImportViteIgnoreWarning(config.customLogger); if (userConfig.coverage?.enabled && !userConfig.coverage.exclude && userConfig.include && config.test) { config.test.coverage = { exclude: [...coverageConfigDefaults.exclude, ...userConfig.include] }; } if (viteConfig.ssr?.noExternal !== true) { const inline = testConfig.server?.deps?.inline; if (inline === true) { config.ssr = { noExternal: true }; } else { const noExternal = viteConfig.ssr?.noExternal; const noExternalArray = typeof noExternal !== "undefined" ? toArray(noExternal) : void 0; const uniqueInline = inline && noExternalArray ? inline.filter((dep) => !noExternalArray.includes(dep)) : inline; config.ssr = { noExternal: uniqueInline }; } } if (process.platform === "darwin" && process.env.VITE_TEST_WATCHER_DEBUG) { const watch = config.server.watch; if (watch) { watch.useFsEvents = false; watch.usePolling = false; } } const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable"; if (classNameStrategy !== "scoped") { config.css ??= {}; config.css.modules ??= {}; if (config.css.modules) { config.css.modules.generateScopedName = (name, filename) => { const root = getRoot(); return generateScopedClassName( classNameStrategy, name, relative(root, filename) ); }; } } return config; }, async configResolved(viteConfig) { const viteConfigTest = viteConfig.test || {}; if (viteConfigTest.watch === false) { viteConfigTest.run = true; } if ("alias" in viteConfigTest) { delete viteConfigTest.alias; } options = deepMerge({}, configDefaults, viteConfigTest, options); options.api = resolveApiServerConfig(options, defaultPort); const { PROD, DEV, ...envs } = viteConfig.env; process.env.PROD ??= PROD ? "1" : ""; process.env.DEV ??= DEV ? "1" : ""; for (const name in envs) { process.env[name] ??= envs[name]; } if (!options.watch) { viteConfig.server.watch = null; } hijackVitePluginInject(viteConfig); }, configureServer: { // runs after vite:import-analysis as it relies on `server` instance on Vite 5 order: "post", async handler(server) { if (options.watch && process.env.VITE_TEST_WATCHER_DEBUG) { server.watcher.on("ready", () => { console.log("[debug] watcher is ready"); }); } await ctx.setServer(options, server, userConfig); if (options.api && options.watch) { (await Promise.resolve().then(function () { return setup$1; })).setup(ctx); } if (!options.watch) { await server.watcher.close(); } } } }, SsrReplacerPlugin(), ...CSSEnablerPlugin(ctx), CoverageTransform(ctx), VitestCoreResolver(ctx), options.ui ? await UIPlugin() : null, ...MocksPlugins(), VitestOptimizer(), NormalizeURLPlugin() ].filter(notNullish); } function removeUndefinedValues(obj) { for (const key in Object.keys(obj)) { if (obj[key] === void 0) { delete obj[key]; } } return obj; } async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) { const ctx = new Vitest(mode, vitestOptions); const root = slash(resolve$1(options.root || process.cwd())); const configPath = options.config === false ? false : options.config ? resolve$1(root, options.config) : await findUp(configFiles, { cwd: root }); options.config = configPath; const config = { configFile: configPath, // this will make "mode": "test" | "benchmark" inside defineConfig mode: options.mode || mode, plugins: await VitestPlugin(options, ctx) }; const server = await createViteServer( mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })) ); if (ctx.config.api?.port) { await server.listen(); } return ctx; } const MAX_RESULT_COUNT = 10; const SELECTION_MAX_INDEX = 7; const ESC = "\x1B["; class WatchFilter { filterRL; currentKeyword = void 0; message; results = []; selectionIndex = -1; onKeyPress; stdin; stdout; constructor(message, stdin = process.stdin, stdout$1 = stdout()) { this.message = message; this.stdin = stdin; this.stdout = stdout$1; this.filterRL = readline.createInterface({ input: this.stdin, escapeCodeTimeout: 50 }); readline.emitKeypressEvents(this.stdin, this.filterRL); if (this.stdin.isTTY) { this.stdin.setRawMode(true); } } async filter(filterFunc) { this.write(this.promptLine()); const resultPromise = createDefer(); this.onKeyPress = this.filterHandler(filterFunc, (result) => { resultPromise.resolve(result); }); this.stdin.on("keypress", this.onKeyPress); try { return await resultPromise; } finally { this.close(); } } filterHandler(filterFunc, onSubmit) { return async (str, key) => { switch (true) { case key.sequence === "\x7F": if (this.currentKeyword && this.currentKeyword?.length > 1) { this.currentKeyword = this.currentKeyword?.slice(0, -1); } else { this.currentKeyword = void 0; } break; case (key?.ctrl && key?.name === "c"): case key?.name === "escape": this.write(`${ESC}1G${ESC}0J`); onSubmit(void 0); return; case key?.name === "enter": case key?.name === "return": onSubmit( this.results[this.selectionIndex] || this.currentKeyword || "" ); this.currentKeyword = void 0; break; case key?.name === "up": if (this.selectionIndex && this.selectionIndex > 0) { this.selectionIndex--; } else { this.selectionIndex = -1; } break; case key?.name === "down": if (this.selectionIndex < this.results.length - 1) { this.selectionIndex++; } else if (this.selectionIndex >= this.results.length - 1) { this.selectionIndex = this.results.length - 1; } break; case (!key?.ctrl && !key?.meta): if (this.currentKeyword === void 0) { this.currentKeyword = str; } else { this.currentKeyword += str || ""; } break; } if (this.currentKeyword) { this.results = await filterFunc(this.currentKeyword); } this.render(); }; } render() { let printStr = this.promptLine(); if (!this.currentKeyword) { printStr += "\nPlease input filter pattern"; } else if (this.currentKeyword && this.results.length === 0) { printStr += "\nPattern matches no results"; } else { const resultCountLine = this.results.length === 1 ? `Pattern matches ${this.results.length} result` : `Pattern matches ${this.results.length} results`; let resultBody = ""; if (this.results.length > MAX_RESULT_COUNT) { const offset = this.selectionIndex > SELECTION_MAX_INDEX ? this.selectionIndex - SELECTION_MAX_INDEX : 0; const displayResults = this.results.slice( offset, MAX_RESULT_COUNT + offset ); const remainingResultCount = this.results.length - offset - displayResults.length; resultBody = `${displayResults.map( (result, index) => index + offset === this.selectionIndex ? c.green(` \u203A ${result}`) : c.dim(` \u203A ${result}`) ).join("\n")}`; if (remainingResultCount > 0) { resultBody += ` ${c.dim( ` ...and ${remainingResultCount} more ${remainingResultCount === 1 ? "result" : "results"}` )}`; } } else { resultBody = this.results.map( (result, index) => index === this.selectionIndex ? c.green(` \u203A ${result}`) : c.dim(` \u203A ${result}`) ).join("\n"); } printStr += ` ${resultCountLine} ${resultBody}`; } this.eraseAndPrint(printStr); this.restoreCursor(); } keywordOffset() { return `? ${this.message} \u203A `.length + 1; } promptLine() { return `${c.cyan("?")} ${c.bold(this.message)} \u203A ${this.currentKeyword || ""}`; } eraseAndPrint(str) { let rows = 0; const lines = str.split(/\r?\n/); for (const line of lines) { const columns = "columns" in this.stdout ? this.stdout.columns : 80; rows += 1 + Math.floor(Math.max(stripVTControlCharacters(line).length - 1, 0) / columns); } this.write(`${ESC}1G`); this.write(`${ESC}J`); this.write(str); this.write(`${ESC}${rows - 1}A`); } close() { this.filterRL.close(); if (this.onKeyPress) { this.stdin.removeListener("keypress", this.onKeyPress); } if (this.stdin.isTTY) { this.stdin.setRawMode(false); } } restoreCursor() { const cursortPos = this.keywordOffset() + (this.currentKeyword?.length || 0); this.write(`${ESC}${cursortPos}G`); } write(data) { this.stdout.write(data); } getLastResults() { return this.results; } } const keys = [ [["a", "return"], "rerun all tests"], ["r", "rerun current pattern tests"], ["f", "rerun only failed tests"], ["u", "update snapshot"], ["p", "filter by a filename"], ["t", "filter by a test name regex pattern"], ["w", "filter by a project name"], ["b", "start the browser server if not started yet"], ["q", "quit"] ]; const cancelKeys = ["space", "c", "h", ...keys.map((key) => key[0]).flat()]; function printShortcutsHelp() { stdout().write( ` ${c.bold(" Watch Usage")} ${keys.map( (i) => c.dim(" press ") + c.reset([i[0]].flat().map(c.bold).join(", ")) + c.dim(` to ${i[1]}`) ).join("\n")} ` ); } function registerConsoleShortcuts(ctx, stdin = process.stdin, stdout2) { let latestFilename = ""; async function _keypressHandler(str, key) { if (str === "" || str === "\x1B" || key && key.ctrl && key.name === "c") { if (!ctx.isCancelling) { ctx.logger.logUpdate.clear(); ctx.logger.log( c.red("Cancelling test run. Press CTRL+c again to exit forcefully.\n") ); process.exitCode = 130; await ctx.cancelCurrentRun("keyboard-input"); await ctx.runningPromise; } return ctx.exit(true); } if (!isWindows && key && key.ctrl && key.name === "z") { process.kill(process.ppid, "SIGTSTP"); process.kill(process.pid, "SIGTSTP"); return; } const name = key?.name; if (ctx.runningPromise) { if (cancelKeys.includes(name)) { await ctx.cancelCurrentRun("keyboard-input"); } return; } if (name === "q") { return ctx.exit(true); } if (name === "h") { return printShortcutsHelp(); } if (name === "u") { return ctx.updateSnapshot(); } if (name === "a" || name === "return") { const files = await ctx.getTestFilepaths(); return ctx.changeNamePattern("", files, "rerun all tests"); } if (name === "r") { return ctx.rerunFiles(); } if (name === "f") { return ctx.rerunFailed(); } if (name === "w") { return inputProjectName(); } if (name === "t") { return inputNamePattern(); } if (name === "p") { return inputFilePattern(); } if (name === "b") { await ctx.initBrowserServers(); ctx.projects.forEach((project) => { ctx.logger.log(); ctx.logger.printBrowserBanner(project); }); return null; } } async function keypressHandler(str, key) { await _keypressHandler(str, key); } async function inputNamePattern() { off(); const watchFilter = new WatchFilter( "Input test name pattern (RegExp)", stdin, stdout2 ); const filter = await watchFilter.filter((str) => { const files2 = ctx.state.getFiles(); const tests = getTests(files2); try { const reg = new RegExp(str); return tests.map((test) => test.name).filter((testName) => testName.match(reg)); } catch { return []; } }); on(); if (typeof filter === "undefined") { return; } const files = ctx.state.getFilepaths(); const cliFiles = ctx.config.standalone && !files.length ? await ctx.getTestFilepaths() : void 0; await ctx.changeNamePattern( filter?.trim() || "", cliFiles, "change pattern" ); } async function inputProjectName() { off(); const { filter = "" } = await prompt([ { name: "filter", type: "text", message: "Input a single project name", initial: toArray(ctx.configOverride.project)[0] || "" } ]); on(); await ctx.changeProjectName(filter.trim()); } async function inputFilePattern() { off(); const watchFilter = new WatchFilter( "Input filename pattern", stdin, stdout2 ); const filter = await watchFilter.filter(async (str) => { const files = await ctx.globTestFiles([str]); return files.map((file) => relative(ctx.config.root, file[1])); }); on(); if (typeof filter === "undefined") { return; } latestFilename = filter?.trim() || ""; const lastResults = watchFilter.getLastResults(); await ctx.changeFilenamePattern( latestFilename, filter && lastResults.length ? lastResults.map((i) => resolve(ctx.config.root, i)) : void 0 ); } let rl; function on() { off(); rl = readline.createInterface({ input: stdin, escapeCodeTimeout: 50 }); readline.emitKeypressEvents(stdin, rl); if (stdin.isTTY) { stdin.setRawMode(true); } stdin.on("keypress", keypressHandler); } function off() { rl?.close(); rl = void 0; stdin.removeListener("keypress", keypressHandler); if (stdin.isTTY) { stdin.setRawMode(false); } } on(); return function cleanup() { off(); }; } async function startVitest(mode, cliFilters = [], options = {}, viteOverrides, vitestOptions) { const root = resolve(options.root || process.cwd()); const ctx = await prepareVitest( mode, options, viteOverrides, vitestOptions ); if (mode === "test" && ctx.config.coverage.enabled) { const provider = ctx.config.coverage.provider || "v8"; const requiredPackages = CoverageProviderMap[provider]; if (requiredPackages) { if (!await ctx.packageInstaller.ensureInstalled(requiredPackages, root, ctx.version)) { process.exitCode = 1; return ctx; } } } const stdin = vitestOptions?.stdin || process.stdin; const stdout = vitestOptions?.stdout || process.stdout; let stdinCleanup; if (stdin.isTTY && ctx.config.watch) { stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout); } ctx.onAfterSetServer(() => { if (ctx.config.standalone) { ctx.init(); } else { ctx.start(cliFilters); } }); try { if (ctx.config.mergeReports) { await ctx.mergeReports(); } else if (ctx.config.standalone) { await ctx.init(); } else { await ctx.start(cliFilters); } } catch (e) { if (e instanceof FilesNotFoundError) { return ctx; } if (e instanceof GitNotFoundError) { ctx.logger.error(e.message); return ctx; } process.exitCode = 1; ctx.logger.printError(e, { fullStack: true, type: "Unhandled Error" }); ctx.logger.error("\n\n"); return ctx; } if (ctx.shouldKeepServer()) { return ctx; } stdinCleanup?.(); await ctx.close(); return ctx; } async function prepareVitest(mode, options = {}, viteOverrides, vitestOptions) { process.env.TEST = "true"; process.env.VITEST = "true"; process.env.NODE_ENV ??= "test"; if (options.run) { options.watch = false; } const root = resolve(options.root || process.cwd()); if (typeof options.browser === "object" && !("enabled" in options.browser)) { options.browser.enabled = true; } if (typeof options.typecheck?.only === "boolean") { options.typecheck.enabled ??= true; } const ctx = await createVitest(mode, options, viteOverrides, vitestOptions); const environmentPackage = getEnvPackageName(ctx.config.environment); if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) { process.exitCode = 1; return ctx; } return ctx; } function processCollected(ctx, files, options) { let errorsPrinted = false; forEachSuite(files, (suite) => { const errors = suite.result?.errors || []; errors.forEach((error) => { errorsPrinted = true; ctx.logger.printError(error, { project: ctx.getProjectByName(suite.file.projectName) }); }); }); if (errorsPrinted) { return; } if (typeof options.json !== "undefined") { return processJsonOutput(files, options); } return formatCollectedAsString(files).forEach((test) => console.log(test)); } function outputFileList(files, options) { if (typeof options.json !== "undefined") { return outputJsonFileList(files, options); } return formatFilesAsString(files, options).map((file) => console.log(file)); } function outputJsonFileList(files, options) { if (typeof options.json === "boolean") { return console.log(JSON.stringify(formatFilesAsJSON(files), null, 2)); } if (typeof options.json === "string") { const jsonPath = resolve(options.root || process.cwd(), options.json); mkdirSync(dirname(jsonPath), { recursive: true }); writeFileSync(jsonPath, JSON.stringify(formatFilesAsJSON(files), null, 2)); } } function formatFilesAsJSON(files) { return files.map((file) => { const result = { file: file.moduleId }; if (file.project.name) { result.projectName = file.project.name; } return result; }); } function formatFilesAsString(files, options) { return files.map((file) => { let name = relative(options.root || process.cwd(), file.moduleId); if (file.project.name) { name = `[${file.project.name}] ${name}`; } return name; }); } function processJsonOutput(files, options) { if (typeof options.json === "boolean") { return console.log(JSON.stringify(formatCollectedAsJSON(files), null, 2)); } if (typeof options.json === "string") { const jsonPath = resolve(options.root || process.cwd(), options.json); mkdirSync(dirname(jsonPath), { recursive: true }); writeFileSync(jsonPath, JSON.stringify(formatCollectedAsJSON(files), null, 2)); } } function forEachSuite(tasks, callback) { tasks.forEach((task) => { if (task.type === "suite") { callback(task); forEachSuite(task.tasks, callback); } }); } function formatCollectedAsJSON(files) { return files.map((file) => { const tests = getTests(file).filter((test) => test.mode === "run" || test.mode === "only"); return tests.map((test) => { const result = { name: getNames(test).slice(1).join(" > "), file: file.filepath }; if (test.file.projectName) { result.projectName = test.file.projectName; } if (test.location) { result.location = test.location; } return result; }); }).flat(); } function formatCollectedAsString(files) { return files.map((file) => { const tests = getTests(file).filter((test) => test.mode === "run" || test.mode === "only"); return tests.map((test) => { const name = getNames(test).join(" > "); if (test.file.projectName) { return `[${test.file.projectName}] ${name}`; } return name; }); }).flat(); } const envPackageNames = { "jsdom": "jsdom", "happy-dom": "happy-dom", "edge-runtime": "@edge-runtime/vm" }; function getEnvPackageName(env) { if (env === "node") { return null; } if (env in envPackageNames) { return envPackageNames[env]; } if (env[0] === "." || env[0] === "/") { return null; } return `vitest-environment-${env}`; } var cliApi = /*#__PURE__*/Object.freeze({ __proto__: null, formatCollectedAsJSON: formatCollectedAsJSON, formatCollectedAsString: formatCollectedAsString, outputFileList: outputFileList, prepareVitest: prepareVitest, processCollected: processCollected, startVitest: startVitest }); export { FilesNotFoundError as F, GitNotFoundError as G, TestSpecification as T, VitestPackageInstaller as V, VitestPlugin as a, registerConsoleShortcuts as b, createVitest as c, createViteLogger as d, cliApi as e, isValidApiRequest as i, resolveFsAllow as r, startVitest as s };