import { dirname, join, resolve, relative, normalize, basename, toNamespacedPath, isAbsolute } from 'pathe'; import { A as API_PATH, d as defaultPort, e as extraInlineDeps, a as defaultBrowserPort, b as defaultInspectPort, E as EXIT_CODE_RESTART, w as workspacesFiles, C as CONFIG_NAMES, c as configFiles } from './constants.5J7I254_.js'; import { g as getCoverageProvider, C as CoverageProviderMap } from './coverage.E7sG1b3r.js'; import { g as getEnvPackageName } from './index.GVFv9dZ0.js'; import { isFileServingAllowed, searchForWorkspaceRoot, version as version$1, createServer, mergeConfig } from 'vite'; import path$8 from 'node:path'; import url, { fileURLToPath } from 'node:url'; import process$1 from 'node:process'; import fs$8, { promises as promises$1, existsSync, readFileSync } from 'node:fs'; import { MessageChannel, isMainThread } from 'node:worker_threads'; import { c as commonjsGlobal, g as getDefaultExportFromCjs } from './_commonjsHelpers.jjO7Zipk.js'; import require$$0 from 'os'; import p from 'path'; import { a as micromatch_1, m as mm } from './index.xL8XjTLv.js'; import require$$0$1 from 'stream'; import require$$0$3 from 'events'; import require$$0$2 from 'fs'; import c from 'picocolors'; import { ViteNodeRunner } from 'vite-node/client'; import { SnapshotManager } from '@vitest/snapshot/manager'; import { ViteNodeServer } from 'vite-node/server'; import { hasFailed, getTasks, getTests } from '@vitest/runner/utils'; import { n as noop$2, b as isPrimitive, c as groupBy, A as AggregateErrorPonyfill, a as slash$1, t as toArray, d as deepMerge, e as nanoid, w as wildcardPatternToRegExp, f as stdout } from './base.5NT-gWu5.js'; import { createDefer, toArray as toArray$1, notNullish } from '@vitest/utils'; import { a as isWindows } from './env.AtSIuHFg.js'; import { rootDir } from '../path.js'; import { c as createBirpc } from './index.8bPxjt7g.js'; import require$$0$4 from 'zlib'; import require$$0$5 from 'buffer'; import require$$1 from 'crypto'; 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 { parseErrorStacktrace } from '@vitest/utils/source-map'; import crypto, { createHash as createHash$2 } from 'node:crypto'; import v8 from 'node:v8'; import * as nodeos from 'node:os'; import nodeos__default, { tmpdir } from 'node:os'; import EventEmitter$2 from 'node:events'; import Tinypool$1, { Tinypool } from 'tinypool'; import { w as wrapSerializableConfig, f as Typechecker, R as ReportersMap, e as BenchmarkReportsMap, g as RandomSequencer, B as BaseSequencer, h as generateCodeFrame, i as highlightCode, L as Logger } from './index.-xs08BYx.js'; import { mkdir, writeFile, rm } from 'node:fs/promises'; import { resolveModule, isPackageExists } from 'local-pkg'; import { isCI, provider as provider$1 } from 'std-env'; import { v as version } from './cac.cdAtVkJZ.js'; import { normalizeRequestId, cleanUrl } from 'vite-node/utils'; import MagicString from 'magic-string'; import { findNodeAround } from 'acorn-walk'; import { esmWalker } from '@vitest/utils/ast'; import { stripLiteral } from 'strip-literal'; import { d as divider, s as stripAnsi } from './utils.dEtNIEgr.js'; import { createRequire } from 'node:module'; import { a as removeUndefinedValues } from './index.SMVOaj7F.js'; import readline from 'node:readline'; import require$$0$6 from 'readline'; function _mergeNamespaces(n, m) { m.forEach(function (e) { e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) { if (k !== 'default' && !(k in n)) { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); }); return Object.freeze(n); } async function getModuleGraph(ctx, id) { const graph = {}; const externalized = /* @__PURE__ */ new Set(); const inlined = /* @__PURE__ */ new Set(); function clearId(id2) { return (id2 == null ? void 0 : id2.replace(/\?v=\w+$/, "")) || ""; } async function get(mod, seen = /* @__PURE__ */ new Map()) { if (!mod || !mod.id) return; if (seen.has(mod)) return seen.get(mod); let id2 = clearId(mod.id); seen.set(mod, id2); const rewrote = await ctx.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; } await get(ctx.server.moduleGraph.getModuleById(id)); return { graph, externalized: Array.from(externalized), inlined: Array.from(inlined) }; } function cloneByOwnProperties(value) { return Object.getOwnPropertyNames(value).reduce((clone, prop) => ({ ...clone, [prop]: value[prop] }), {}); } function stringifyReplace(key, value) { if (value instanceof Error) return cloneByOwnProperties(value); else return value; } /* How it works: `this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value. */ class Node { value; next; constructor(value) { this.value = value; } } class Queue { #head; #tail; #size; constructor() { this.clear(); } enqueue(value) { const node = new Node(value); if (this.#head) { this.#tail.next = node; this.#tail = node; } else { this.#head = node; this.#tail = node; } this.#size++; } dequeue() { const current = this.#head; if (!current) { return; } this.#head = this.#head.next; this.#size--; return current.value; } clear() { this.#head = undefined; this.#tail = undefined; this.#size = 0; } get size() { return this.#size; } * [Symbol.iterator]() { let current = this.#head; while (current) { yield current.value; current = current.next; } } } function pLimit(concurrency) { if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) { throw new TypeError('Expected `concurrency` to be a number from 1 and up'); } const queue = new Queue(); let activeCount = 0; const next = () => { activeCount--; if (queue.size > 0) { queue.dequeue()(); } }; const run = async (fn, resolve, args) => { activeCount++; const result = (async () => fn(...args))(); resolve(result); try { await result; } catch {} next(); }; const enqueue = (fn, resolve, args) => { queue.enqueue(run.bind(undefined, fn, resolve, args)); (async () => { // This function needs to wait until the next microtask before comparing // `activeCount` to `concurrency`, because `activeCount` is updated asynchronously // when the run function is dequeued and called. The comparison in the if-statement // needs to happen asynchronously as well to get an up-to-date value for `activeCount`. await Promise.resolve(); if (activeCount < concurrency && queue.size > 0) { queue.dequeue()(); } })(); }; const generator = (fn, ...args) => new Promise(resolve => { enqueue(fn, resolve, args); }); Object.defineProperties(generator, { activeCount: { get: () => activeCount, }, pendingCount: { get: () => queue.size, }, clearQueue: { value: () => { queue.clear(); }, }, }); return generator; } class EndError extends Error { constructor(value) { super(); this.value = value; } } // The input can also be a promise, so we await it. const testElement = async (element, tester) => tester(await element); // The input can also be a promise, so we `Promise.all()` them both. const finder = async element => { const values = await Promise.all(element); if (values[1] === true) { throw new EndError(values[0]); } return false; }; async function pLocate( iterable, tester, { concurrency = Number.POSITIVE_INFINITY, preserveOrder = true, } = {}, ) { const limit = pLimit(concurrency); // Start all the promises concurrently with optional limit. const items = [...iterable].map(element => [element, limit(testElement, element, tester)]); // Check the promises either serially or concurrently. const checkLimit = pLimit(preserveOrder ? 1 : Number.POSITIVE_INFINITY); try { await Promise.all(items.map(element => checkLimit(finder, element))); } catch (error) { if (error instanceof EndError) { return error.value; } throw error; } } const typeMappings = { directory: 'isDirectory', file: 'isFile', }; function checkType(type) { if (Object.hasOwnProperty.call(typeMappings, type)) { return; } throw new Error(`Invalid type specified: ${type}`); } const matchType = (type, stat) => stat[typeMappings[type]](); const toPath$1 = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath; async function locatePath( paths, { cwd = process$1.cwd(), type = 'file', allowSymlinks = true, concurrency, preserveOrder, } = {}, ) { checkType(type); cwd = toPath$1(cwd); const statFunction = allowSymlinks ? promises$1.stat : promises$1.lstat; return pLocate(paths, async path_ => { try { const stat = await statFunction(path$8.resolve(cwd, path_)); return matchType(type, stat); } catch { return false; } }, {concurrency, preserveOrder}); } const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath; const findUpStop = Symbol('findUpStop'); async function findUpMultiple(name, options = {}) { let directory = path$8.resolve(toPath(options.cwd) || ''); const {root} = path$8.parse(directory); const stopAt = path$8.resolve(directory, options.stopAt || root); const limit = options.limit || Number.POSITIVE_INFINITY; const paths = [name].flat(); const runMatcher = async locateOptions => { if (typeof name !== 'function') { return locatePath(paths, locateOptions); } const foundPath = await name(locateOptions.cwd); if (typeof foundPath === 'string') { return locatePath([foundPath], locateOptions); } return foundPath; }; const matches = []; // eslint-disable-next-line no-constant-condition while (true) { // eslint-disable-next-line no-await-in-loop const foundPath = await runMatcher({...options, cwd: directory}); if (foundPath === findUpStop) { break; } if (foundPath) { matches.push(path$8.resolve(directory, foundPath)); } if (directory === stopAt || matches.length >= limit) { break; } directory = path$8.dirname(directory); } return matches; } async function findUp(name, options = {}) { const matches = await findUpMultiple(name, {...options, limit: 1}); return matches[0]; } var tasks = {}; var utils$b = {}; var array$1 = {}; Object.defineProperty(array$1, "__esModule", { value: true }); array$1.splitWhen = array$1.flatten = void 0; function flatten(items) { return items.reduce((collection, item) => [].concat(collection, item), []); } array$1.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$1.splitWhen = splitWhen; var errno$1 = {}; Object.defineProperty(errno$1, "__esModule", { value: true }); errno$1.isEnoentCodeError = void 0; function isEnoentCodeError(error) { return error.code === 'ENOENT'; } errno$1.isEnoentCodeError = isEnoentCodeError; var fs$7 = {}; Object.defineProperty(fs$7, "__esModule", { value: true }); fs$7.createDirentFromStats = void 0; let DirentFromStats$1 = 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$1(name, stats) { return new DirentFromStats$1(name, stats); } fs$7.createDirentFromStats = createDirentFromStats$1; var path$7 = {}; Object.defineProperty(path$7, "__esModule", { value: true }); path$7.convertPosixPathToPattern = path$7.convertWindowsPathToPattern = path$7.convertPathToPattern = path$7.escapePosixPath = path$7.escapeWindowsPath = path$7.escape = path$7.removeLeadingDotSegment = path$7.makeAbsolute = path$7.unixify = void 0; const os = require$$0; const path$6 = p; 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$7.unixify = unixify; function makeAbsolute(cwd, filepath) { return path$6.resolve(cwd, filepath); } path$7.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$7.removeLeadingDotSegment = removeLeadingDotSegment; path$7.escape = IS_WINDOWS_PLATFORM ? escapeWindowsPath : escapePosixPath; function escapeWindowsPath(pattern) { return pattern.replace(WINDOWS_UNESCAPED_GLOB_SYMBOLS_RE, '\\$2'); } path$7.escapeWindowsPath = escapeWindowsPath; function escapePosixPath(pattern) { return pattern.replace(POSIX_UNESCAPED_GLOB_SYMBOLS_RE, '\\$2'); } path$7.escapePosixPath = escapePosixPath; path$7.convertPathToPattern = IS_WINDOWS_PLATFORM ? convertWindowsPathToPattern : convertPosixPathToPattern; function convertWindowsPathToPattern(filepath) { return escapeWindowsPath(filepath) .replace(DOS_DEVICE_PATH_RE, '//$1') .replace(WINDOWS_BACKSLASHES_RE, '/'); } path$7.convertWindowsPathToPattern = convertWindowsPathToPattern; function convertPosixPathToPattern(filepath) { return escapePosixPath(filepath); } path$7.convertPosixPathToPattern = convertPosixPathToPattern; var pattern$1 = {}; /*! * is-extglob * * Copyright (c) 2014-2016, Jon Schlinkert. * Licensed under the MIT License. */ var isExtglob$1 = 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; }; /*! * is-glob * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. */ var isExtglob = isExtglob$1; 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; }; var isGlob$1 = 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); }; var isGlob = isGlob$1; var pathPosixDirname = p.posix.dirname; var isWin32 = require$$0.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} */ var globParent$1 = 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'); }; Object.defineProperty(pattern$1, "__esModule", { value: true }); pattern$1.removeDuplicateSlashes = pattern$1.matchAny = pattern$1.convertPatternsToRe = pattern$1.makeRe = pattern$1.getPatternParts = pattern$1.expandBraceExpansion = pattern$1.expandPatternsWithBraceExpansion = pattern$1.isAffectDepthOfReadingPattern = pattern$1.endsWithSlashGlobStar = pattern$1.hasGlobStar = pattern$1.getBaseDirectory = pattern$1.isPatternRelatedToParentDirectory = pattern$1.getPatternsOutsideCurrentDirectory = pattern$1.getPatternsInsideCurrentDirectory = pattern$1.getPositivePatterns = pattern$1.getNegativePatterns = pattern$1.isPositivePattern = pattern$1.isNegativePattern = pattern$1.convertToNegativePattern = pattern$1.convertToPositivePattern = pattern$1.isDynamicPattern = pattern$1.isStaticPattern = void 0; const path$5 = p; const globParent = globParent$1; const micromatch = micromatch_1; 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$1.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$1.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$1.convertToPositivePattern = convertToPositivePattern; function convertToNegativePattern(pattern) { return '!' + pattern; } pattern$1.convertToNegativePattern = convertToNegativePattern; function isNegativePattern(pattern) { return pattern.startsWith('!') && pattern[1] !== '('; } pattern$1.isNegativePattern = isNegativePattern; function isPositivePattern(pattern) { return !isNegativePattern(pattern); } pattern$1.isPositivePattern = isPositivePattern; function getNegativePatterns(patterns) { return patterns.filter(isNegativePattern); } pattern$1.getNegativePatterns = getNegativePatterns; function getPositivePatterns$1(patterns) { return patterns.filter(isPositivePattern); } pattern$1.getPositivePatterns = getPositivePatterns$1; /** * Returns patterns that can be applied inside the current directory. * * @example * // ['./*', '*', 'a/*'] * getPatternsInsideCurrentDirectory(['./*', '*', 'a/*', '../*', './../*']) */ function getPatternsInsideCurrentDirectory(patterns) { return patterns.filter((pattern) => !isPatternRelatedToParentDirectory(pattern)); } pattern$1.getPatternsInsideCurrentDirectory = getPatternsInsideCurrentDirectory; /** * Returns patterns to be expanded relative to (outside) the current directory. * * @example * // ['../*', './../*'] * getPatternsInsideCurrentDirectory(['./*', '*', 'a/*', '../*', './../*']) */ function getPatternsOutsideCurrentDirectory(patterns) { return patterns.filter(isPatternRelatedToParentDirectory); } pattern$1.getPatternsOutsideCurrentDirectory = getPatternsOutsideCurrentDirectory; function isPatternRelatedToParentDirectory(pattern) { return pattern.startsWith('..') || pattern.startsWith('./..'); } pattern$1.isPatternRelatedToParentDirectory = isPatternRelatedToParentDirectory; function getBaseDirectory(pattern) { return globParent(pattern, { flipBackslashes: false }); } pattern$1.getBaseDirectory = getBaseDirectory; function hasGlobStar(pattern) { return pattern.includes(GLOBSTAR); } pattern$1.hasGlobStar = hasGlobStar; function endsWithSlashGlobStar(pattern) { return pattern.endsWith('/' + GLOBSTAR); } pattern$1.endsWithSlashGlobStar = endsWithSlashGlobStar; function isAffectDepthOfReadingPattern(pattern) { const basename = path$5.basename(pattern); return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); } pattern$1.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; function expandPatternsWithBraceExpansion(patterns) { return patterns.reduce((collection, pattern) => { return collection.concat(expandBraceExpansion(pattern)); }, []); } pattern$1.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$1.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$1.getPatternParts = getPatternParts; function makeRe(pattern, options) { return micromatch.makeRe(pattern, options); } pattern$1.makeRe = makeRe; function convertPatternsToRe(patterns, options) { return patterns.map((pattern) => makeRe(pattern, options)); } pattern$1.convertPatternsToRe = convertPatternsToRe; function matchAny(entry, patternsRe) { return patternsRe.some((patternRe) => patternRe.test(entry)); } pattern$1.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$1.removeDuplicateSlashes = removeDuplicateSlashes; var stream$4 = {}; /* * merge2 * https://github.com/teambition/merge2 * * Copyright (c) 2014-2020 Teambition * Licensed under the MIT license. */ const Stream = require$$0$1; const PassThrough = Stream.PassThrough; const slice = Array.prototype.slice; var merge2_1 = merge2$1; function merge2$1 () { 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 } Object.defineProperty(stream$4, "__esModule", { value: true }); stream$4.merge = void 0; const merge2 = merge2_1; 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$4.merge = merge; function propagateCloseEventToSources(streams) { streams.forEach((stream) => stream.emit('close')); } var string$1 = {}; Object.defineProperty(string$1, "__esModule", { value: true }); string$1.isEmpty = string$1.isString = void 0; function isString(input) { return typeof input === 'string'; } string$1.isString = isString; function isEmpty(input) { return input === ''; } string$1.isEmpty = isEmpty; Object.defineProperty(utils$b, "__esModule", { value: true }); utils$b.string = utils$b.stream = utils$b.pattern = utils$b.path = utils$b.fs = utils$b.errno = utils$b.array = void 0; const array = array$1; utils$b.array = array; const errno = errno$1; utils$b.errno = errno; const fs$6 = fs$7; utils$b.fs = fs$6; const path$4 = path$7; utils$b.path = path$4; const pattern = pattern$1; utils$b.pattern = pattern; const stream$3 = stream$4; utils$b.stream = stream$3; const string = string$1; utils$b.string = string; Object.defineProperty(tasks, "__esModule", { value: true }); tasks.convertPatternGroupToTask = tasks.convertPatternGroupsToTasks = tasks.groupPatternsByBaseDirectory = tasks.getNegativePatternsAsPositive = tasks.getPositivePatterns = tasks.convertPatternsToTasks = tasks.generate = void 0; const utils$a = utils$b; 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$a.pattern.isStaticPattern(pattern, settings)); const dynamicPatterns = positivePatterns.filter((pattern) => utils$a.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$a.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$a.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$a.pattern.getPatternsOutsideCurrentDirectory(positive); const patternsInsideCurrentDirectory = utils$a.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$a.pattern.getPositivePatterns(patterns); } tasks.getPositivePatterns = getPositivePatterns; function getNegativePatternsAsPositive(patterns, ignore) { const negative = utils$a.pattern.getNegativePatterns(patterns).concat(ignore); const positive = negative.map(utils$a.pattern.convertToPositivePattern); return positive; } tasks.getNegativePatternsAsPositive = getNegativePatternsAsPositive; function groupPatternsByBaseDirectory(patterns) { const group = {}; return patterns.reduce((collection, pattern) => { const base = utils$a.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$a.pattern.convertToNegativePattern)) }; } tasks.convertPatternGroupToTask = convertPatternGroupToTask; var async$7 = {}; var async$6 = {}; var out$3 = {}; var async$5 = {}; var async$4 = {}; var out$2 = {}; var async$3 = {}; var out$1 = {}; var async$2 = {}; Object.defineProperty(async$2, "__esModule", { value: true }); async$2.read = void 0; function read$3(path, settings, callback) { settings.fs.lstat(path, (lstatError, lstat) => { if (lstatError !== null) { callFailureCallback$2(callback, lstatError); return; } if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { callSuccessCallback$2(callback, lstat); return; } settings.fs.stat(path, (statError, stat) => { if (statError !== null) { if (settings.throwErrorOnBrokenSymbolicLink) { callFailureCallback$2(callback, statError); return; } callSuccessCallback$2(callback, lstat); return; } if (settings.markSymbolicLink) { stat.isSymbolicLink = () => true; } callSuccessCallback$2(callback, stat); }); }); } async$2.read = read$3; function callFailureCallback$2(callback, error) { callback(error); } function callSuccessCallback$2(callback, result) { callback(null, result); } var sync$7 = {}; Object.defineProperty(sync$7, "__esModule", { value: true }); sync$7.read = void 0; function read$2(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$7.read = read$2; var settings$3 = {}; var fs$5 = {}; (function (exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0; const fs = require$$0$2; 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$5)); Object.defineProperty(settings$3, "__esModule", { value: true }); const fs$4 = fs$5; let Settings$2 = class Settings { constructor(_options = {}) { this._options = _options; this.followSymbolicLink = this._getValue(this._options.followSymbolicLink, true); this.fs = fs$4.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$2; Object.defineProperty(out$1, "__esModule", { value: true }); out$1.statSync = out$1.stat = out$1.Settings = void 0; const async$1 = async$2; const sync$6 = sync$7; const settings_1$3 = settings$3; out$1.Settings = settings_1$3.default; function stat(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { async$1.read(path, getSettings$2(), optionsOrSettingsOrCallback); return; } async$1.read(path, getSettings$2(optionsOrSettingsOrCallback), callback); } out$1.stat = stat; function statSync(path, optionsOrSettings) { const settings = getSettings$2(optionsOrSettings); return sync$6.read(path, settings); } out$1.statSync = statSync; function getSettings$2(settingsOrOptions = {}) { if (settingsOrOptions instanceof settings_1$3.default) { return settingsOrOptions; } return new settings_1$3.default(settingsOrOptions); } /*! queue-microtask. MIT License. Feross Aboukhadijeh */ let promise$1; var queueMicrotask_1 = typeof queueMicrotask === 'function' ? queueMicrotask.bind(typeof window !== 'undefined' ? window : commonjsGlobal) // reuse resolved promise, and allocate it lazily : cb => (promise$1 || (promise$1 = Promise.resolve())) .then(cb) .catch(err => setTimeout(() => { throw err }, 0)); /*! run-parallel. MIT License. Feross Aboukhadijeh */ var runParallel_1 = runParallel; const queueMicrotask$1 = queueMicrotask_1; 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$1(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; } var constants$1 = {}; Object.defineProperty(constants$1, "__esModule", { value: true }); constants$1.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$1.IS_SUPPORT_READDIR_WITH_FILE_TYPES = IS_MATCHED_BY_MAJOR || IS_MATCHED_BY_MAJOR_AND_MINOR; var utils$9 = {}; var fs$3 = {}; 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; Object.defineProperty(utils$9, "__esModule", { value: true }); utils$9.fs = void 0; const fs$2 = fs$3; utils$9.fs = fs$2; var common$6 = {}; Object.defineProperty(common$6, "__esModule", { value: true }); common$6.joinPathSegments = void 0; function joinPathSegments$1(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$6.joinPathSegments = joinPathSegments$1; Object.defineProperty(async$3, "__esModule", { value: true }); async$3.readdir = async$3.readdirWithFileTypes = async$3.read = void 0; const fsStat$5 = out$1; const rpl = runParallel_1; const constants_1$1 = constants$1; const utils$8 = utils$9; const common$5 = common$6; function read$1(directory, settings, callback) { if (!settings.stats && constants_1$1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { readdirWithFileTypes$1(directory, settings, callback); return; } readdir$1(directory, settings, callback); } async$3.read = read$1; function readdirWithFileTypes$1(directory, settings, callback) { settings.fs.readdir(directory, { withFileTypes: true }, (readdirError, dirents) => { if (readdirError !== null) { callFailureCallback$1(callback, readdirError); return; } const entries = dirents.map((dirent) => ({ dirent, name: dirent.name, path: common$5.joinPathSegments(directory, dirent.name, settings.pathSegmentSeparator) })); if (!settings.followSymbolicLinks) { callSuccessCallback$1(callback, entries); return; } const tasks = entries.map((entry) => makeRplTaskEntry(entry, settings)); rpl(tasks, (rplError, rplEntries) => { if (rplError !== null) { callFailureCallback$1(callback, rplError); return; } callSuccessCallback$1(callback, rplEntries); }); }); } async$3.readdirWithFileTypes = readdirWithFileTypes$1; 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$8.fs.createDirentFromStats(entry.name, stats); done(null, entry); }); }; } function readdir$1(directory, settings, callback) { settings.fs.readdir(directory, (readdirError, names) => { if (readdirError !== null) { callFailureCallback$1(callback, readdirError); return; } const tasks = names.map((name) => { const path = common$5.joinPathSegments(directory, name, settings.pathSegmentSeparator); return (done) => { fsStat$5.stat(path, settings.fsStatSettings, (error, stats) => { if (error !== null) { done(error); return; } const entry = { name, path, dirent: utils$8.fs.createDirentFromStats(name, stats) }; if (settings.stats) { entry.stats = stats; } done(null, entry); }); }; }); rpl(tasks, (rplError, entries) => { if (rplError !== null) { callFailureCallback$1(callback, rplError); return; } callSuccessCallback$1(callback, entries); }); }); } async$3.readdir = readdir$1; function callFailureCallback$1(callback, error) { callback(error); } function callSuccessCallback$1(callback, result) { callback(null, result); } var sync$5 = {}; Object.defineProperty(sync$5, "__esModule", { value: true }); sync$5.readdir = sync$5.readdirWithFileTypes = sync$5.read = void 0; const fsStat$4 = out$1; const constants_1 = constants$1; const utils$7 = utils$9; const common$4 = common$6; function read(directory, settings) { if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { return readdirWithFileTypes(directory, settings); } return readdir(directory, settings); } sync$5.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$4.joinPathSegments(directory, dirent.name, settings.pathSegmentSeparator) }; if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { try { const stats = settings.fs.statSync(entry.path); entry.dirent = utils$7.fs.createDirentFromStats(entry.name, stats); } catch (error) { if (settings.throwErrorOnBrokenSymbolicLink) { throw error; } } } return entry; }); } sync$5.readdirWithFileTypes = readdirWithFileTypes; function readdir(directory, settings) { const names = settings.fs.readdirSync(directory); return names.map((name) => { const entryPath = common$4.joinPathSegments(directory, name, settings.pathSegmentSeparator); const stats = fsStat$4.statSync(entryPath, settings.fsStatSettings); const entry = { name, path: entryPath, dirent: utils$7.fs.createDirentFromStats(name, stats) }; if (settings.stats) { entry.stats = stats; } return entry; }); } sync$5.readdir = readdir; var settings$2 = {}; var fs$1 = {}; (function (exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0; const fs = require$$0$2; 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$1)); Object.defineProperty(settings$2, "__esModule", { value: true }); const path$3 = p; const fsStat$3 = out$1; const fs = fs$1; let Settings$1 = 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$3.sep); this.stats = this._getValue(this._options.stats, false); this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); this.fsStatSettings = new fsStat$3.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$1; Object.defineProperty(out$2, "__esModule", { value: true }); out$2.Settings = out$2.scandirSync = out$2.scandir = void 0; const async = async$3; const sync$4 = sync$5; const settings_1$2 = settings$2; out$2.Settings = settings_1$2.default; function scandir(path, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { async.read(path, getSettings$1(), optionsOrSettingsOrCallback); return; } async.read(path, getSettings$1(optionsOrSettingsOrCallback), callback); } out$2.scandir = scandir; function scandirSync(path, optionsOrSettings) { const settings = getSettings$1(optionsOrSettings); return sync$4.read(path, settings); } out$2.scandirSync = scandirSync; function getSettings$1(settingsOrOptions = {}) { if (settingsOrOptions instanceof settings_1$2.default) { return settingsOrOptions; } return new settings_1$2.default(settingsOrOptions); } var queue = {exports: {}}; function reusify$1 (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 } } var reusify_1 = reusify$1; /* eslint-disable no-var */ var reusify = reusify_1; 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 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$1, saturated: noop$1, pause: pause, paused: false, concurrency: concurrency, running: running, resume: resume, idle: idle, length: length, getQueue: getQueue, unshift: unshift, empty: noop$1, 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; for (var i = 0; i < self.concurrency; i++) { _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$1; current.errorHandler = errorHandler; if (_running === self.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$1; if (_running === self.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) { 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$1; } function killAndDrain () { queueHead = null; queueTail = null; self.drain(); self.drain = noop$1; } function error (handler) { errorHandler = handler; } } function noop$1 () {} function Task () { this.value = null; this.callback = noop$1; this.next = null; this.release = noop$1; 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$1; 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$1); 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$1); return p } function drained () { var previousDrain = queue.drain; var p = new Promise(function (resolve) { queue.drain = function () { previousDrain(); resolve(); }; }); return p } } queue.exports = fastqueue; queue.exports.promise = queueAsPromised; var queueExports = queue.exports; var common$3 = {}; Object.defineProperty(common$3, "__esModule", { value: true }); common$3.joinPathSegments = common$3.replacePathSegmentSeparator = common$3.isAppliedFilter = common$3.isFatalError = void 0; function isFatalError(settings, error) { if (settings.errorFilter === null) { return true; } return !settings.errorFilter(error); } common$3.isFatalError = isFatalError; function isAppliedFilter(filter, value) { return filter === null || filter(value); } common$3.isAppliedFilter = isAppliedFilter; function replacePathSegmentSeparator(filepath, separator) { return filepath.split(/[/\\]/).join(separator); } common$3.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$3.joinPathSegments = joinPathSegments; var reader$1 = {}; Object.defineProperty(reader$1, "__esModule", { value: true }); const common$2 = common$3; let Reader$1 = class Reader { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._root = common$2.replacePathSegmentSeparator(_root, _settings.pathSegmentSeparator); } }; reader$1.default = Reader$1; Object.defineProperty(async$4, "__esModule", { value: true }); const events_1 = require$$0$3; const fsScandir$2 = out$2; const fastq = queueExports; const common$1 = common$3; const reader_1$4 = reader$1; class AsyncReader extends reader_1$4.default { constructor(_root, _settings) { super(_root, _settings); this._settings = _settings; this._scandir = fsScandir$2.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$1.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$1.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); } if (common$1.isAppliedFilter(this._settings.entryFilter, entry)) { this._emitEntry(entry); } if (entry.dirent.isDirectory() && common$1.isAppliedFilter(this._settings.deepFilter, entry)) { this._pushToQueue(fullpath, base === undefined ? undefined : entry.path); } } _emitEntry(entry) { this._emitter.emit('entry', entry); } } async$4.default = AsyncReader; Object.defineProperty(async$5, "__esModule", { value: true }); const async_1$4 = async$4; class AsyncProvider { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._reader = new async_1$4.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$5.default = AsyncProvider; function callFailureCallback(callback, error) { callback(error); } function callSuccessCallback(callback, entries) { callback(null, entries); } var stream$2 = {}; Object.defineProperty(stream$2, "__esModule", { value: true }); const stream_1$5 = require$$0$1; const async_1$3 = async$4; class StreamProvider { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._reader = new async_1$3.default(this._root, this._settings); this._stream = new stream_1$5.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; var sync$3 = {}; var sync$2 = {}; Object.defineProperty(sync$2, "__esModule", { value: true }); const fsScandir$1 = out$2; const common = common$3; const reader_1$3 = reader$1; class SyncReader extends reader_1$3.default { constructor() { super(...arguments); this._scandir = fsScandir$1.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; Object.defineProperty(sync$3, "__esModule", { value: true }); const sync_1$3 = sync$2; class SyncProvider { constructor(_root, _settings) { this._root = _root; this._settings = _settings; this._reader = new sync_1$3.default(this._root, this._settings); } read() { return this._reader.read(); } } sync$3.default = SyncProvider; var settings$1 = {}; Object.defineProperty(settings$1, "__esModule", { value: true }); const path$2 = p; const fsScandir = out$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$2.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; Object.defineProperty(out$3, "__esModule", { value: true }); out$3.Settings = out$3.walkStream = out$3.walkSync = out$3.walk = void 0; const async_1$2 = async$5; const stream_1$4 = stream$2; const sync_1$2 = sync$3; const settings_1$1 = settings$1; out$3.Settings = settings_1$1.default; function walk(directory, optionsOrSettingsOrCallback, callback) { if (typeof optionsOrSettingsOrCallback === 'function') { new async_1$2.default(directory, getSettings()).read(optionsOrSettingsOrCallback); return; } new async_1$2.default(directory, getSettings(optionsOrSettingsOrCallback)).read(callback); } out$3.walk = walk; function walkSync(directory, optionsOrSettings) { const settings = getSettings(optionsOrSettings); const provider = new sync_1$2.default(directory, settings); return provider.read(); } out$3.walkSync = walkSync; function walkStream(directory, optionsOrSettings) { const settings = getSettings(optionsOrSettings); const provider = new stream_1$4.default(directory, settings); return provider.read(); } out$3.walkStream = walkStream; function getSettings(settingsOrOptions = {}) { if (settingsOrOptions instanceof settings_1$1.default) { return settingsOrOptions; } return new settings_1$1.default(settingsOrOptions); } var reader = {}; Object.defineProperty(reader, "__esModule", { value: true }); const path$1 = p; const fsStat$2 = out$1; const utils$6 = utils$b; class Reader { constructor(_settings) { this._settings = _settings; this._fsStatSettings = new fsStat$2.Settings({ followSymbolicLink: this._settings.followSymbolicLinks, fs: this._settings.fs, throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks }); } _getFullEntryPath(filepath) { return path$1.resolve(this._settings.cwd, filepath); } _makeEntry(stats, pattern) { const entry = { name: pattern, path: pattern, dirent: utils$6.fs.createDirentFromStats(pattern, stats) }; if (this._settings.stats) { entry.stats = stats; } return entry; } _isFatalError(error) { return !utils$6.errno.isEnoentCodeError(error) && !this._settings.suppressErrors; } } reader.default = Reader; var stream$1 = {}; Object.defineProperty(stream$1, "__esModule", { value: true }); const stream_1$3 = require$$0$1; const fsStat$1 = out$1; const fsWalk$2 = out$3; const reader_1$2 = reader; class ReaderStream extends reader_1$2.default { constructor() { super(...arguments); this._walkStream = fsWalk$2.walkStream; this._stat = fsStat$1.stat; } dynamic(root, options) { return this._walkStream(root, options); } static(patterns, options) { const filepaths = patterns.map(this._getFullEntryPath, this); const stream = new stream_1$3.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; Object.defineProperty(async$6, "__esModule", { value: true }); const fsWalk$1 = out$3; const reader_1$1 = reader; const stream_1$2 = stream$1; class ReaderAsync extends reader_1$1.default { constructor() { super(...arguments); this._walkAsync = fsWalk$1.walk; this._readerStream = new stream_1$2.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$6.default = ReaderAsync; var provider = {}; var deep = {}; var partial = {}; var matcher = {}; Object.defineProperty(matcher, "__esModule", { value: true }); const utils$5 = utils$b; 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$5.pattern.getPatternParts(pattern, this._micromatchOptions); return parts.map((part) => { const dynamic = utils$5.pattern.isDynamicPattern(part, this._settings); if (!dynamic) { return { dynamic: false, pattern: part }; } return { dynamic: true, pattern: part, patternRe: utils$5.pattern.makeRe(part, this._micromatchOptions) }; }); } _splitSegmentsIntoSections(segments) { return utils$5.array.splitWhen(segments, (segment) => segment.dynamic && utils$5.pattern.hasGlobStar(segment.pattern)); } } matcher.default = Matcher; Object.defineProperty(partial, "__esModule", { value: true }); const matcher_1 = matcher; 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; Object.defineProperty(deep, "__esModule", { value: true }); const utils$4 = utils$b; const partial_1 = partial; 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$4.pattern.isAffectDepthOfReadingPattern); return utils$4.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$4.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$4.pattern.matchAny(entryPath, patternsRe); } } deep.default = DeepFilter; var entry$1 = {}; Object.defineProperty(entry$1, "__esModule", { value: true }); const utils$3 = utils$b; class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; this._micromatchOptions = _micromatchOptions; this.index = new Map(); } getFilter(positive, negative) { const positiveRe = utils$3.pattern.convertPatternsToRe(positive, this._micromatchOptions); const negativeRe = utils$3.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$3.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$3.path.makeAbsolute(this._settings.cwd, entryPath); return utils$3.pattern.matchAny(fullpath, patternsRe); } _isMatchToPatterns(filepath, patternsRe, isDirectory) { // Trying to match files and directories by patterns. const isMatched = utils$3.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$3.pattern.matchAny(filepath + '/', patternsRe); } return isMatched; } } entry$1.default = EntryFilter; var error$1 = {}; Object.defineProperty(error$1, "__esModule", { value: true }); const utils$2 = utils$b; class ErrorFilter { constructor(_settings) { this._settings = _settings; } getFilter() { return (error) => this._isNonFatalError(error); } _isNonFatalError(error) { return utils$2.errno.isEnoentCodeError(error) || this._settings.suppressErrors; } } error$1.default = ErrorFilter; var entry = {}; Object.defineProperty(entry, "__esModule", { value: true }); const utils$1 = utils$b; 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$1.path.makeAbsolute(this._settings.cwd, filepath); filepath = utils$1.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; Object.defineProperty(provider, "__esModule", { value: true }); const path = p; const deep_1 = deep; const entry_1 = entry$1; const error_1 = error$1; const entry_2 = entry; 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; Object.defineProperty(async$7, "__esModule", { value: true }); const async_1$1 = async$6; const provider_1$2 = provider; class ProviderAsync extends provider_1$2.default { constructor() { super(...arguments); this._reader = new async_1$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$7.default = ProviderAsync; var stream = {}; Object.defineProperty(stream, "__esModule", { value: true }); const stream_1$1 = require$$0$1; const stream_2 = stream$1; const provider_1$1 = provider; class ProviderStream extends provider_1$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$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; var sync$1 = {}; var sync = {}; Object.defineProperty(sync, "__esModule", { value: true }); const fsStat = out$1; const fsWalk = out$3; const reader_1 = reader; 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; Object.defineProperty(sync$1, "__esModule", { value: true }); const sync_1$1 = sync; const provider_1 = provider; class ProviderSync extends provider_1.default { constructor() { super(...arguments); this._reader = new sync_1$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; var settings = {}; (function (exports) { Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_FILE_SYSTEM_ADAPTER = void 0; const fs = require$$0$2; const os = require$$0; /** * 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)); const taskManager = tasks; const async_1 = async$7; const stream_1 = stream; const sync_1 = sync$1; const settings_1 = settings; const utils = utils$b; 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'); } } var out = FastGlob; var fg = /*@__PURE__*/getDefaultExportFromCjs(out); /*! (c) 2020 Andrea Giammarchi */ const {parse: $parse, stringify: $stringify} = JSON; const {keys: keys$1} = Object; const Primitive = String; // it could be Number const primitive = 'string'; // it could be 'number' const ignore = {}; const object = 'object'; const noop = (_, value) => value; const primitives = value => ( value instanceof Primitive ? Primitive(value) : value ); const Primitives = (_, value) => ( typeof value === primitive ? new Primitive(value) : value ); const revive = (input, parsed, output, $) => { const lazy = []; for (let ke = keys$1(output), {length} = ke, y = 0; y < length; y++) { const k = ke[y]; const value = output[k]; if (value instanceof Primitive) { const tmp = input[value]; if (typeof tmp === object && !parsed.has(tmp)) { parsed.add(tmp); output[k] = ignore; lazy.push({k, a: [input, parsed, tmp, $]}); } else output[k] = $.call(output, k, tmp); } else if (output[k] !== ignore) output[k] = $.call(output, k, value); } for (let {length} = lazy, i = 0; i < length; i++) { const {k, a} = lazy[i]; output[k] = $.call(output, k, revive.apply(null, a)); } return output; }; const set = (known, input, value) => { const index = Primitive(input.push(value) - 1); known.set(value, index); return index; }; const parse$3 = (text, reviver) => { const input = $parse(text, Primitives).map(primitives); const value = input[0]; const $ = reviver || noop; const tmp = typeof value === object && value ? revive(input, new Set, value, $) : value; return $.call({'': tmp}, '', tmp); }; const stringify = (value, replacer, space) => { const $ = replacer && typeof replacer === object ? (k, v) => (k === '' || -1 < replacer.indexOf(k) ? v : void 0) : (replacer || noop); const known = new Map; const input = []; const output = []; let i = +set(known, input, $.call({'': value}, '', value)); let firstRun = !i; while (i < input.length) { firstRun = true; output[i] = $stringify(input[i++], replace, space); } return '[' + output.join(',') + ']'; function replace(key, value) { if (firstRun) { firstRun = !firstRun; return value; } const after = $.call(this, key, value); switch (typeof after) { case object: if (after === null) return after; case primitive: return known.get(after) || set(known, input, after); } return after; } }; var bufferUtil$1 = {exports: {}}; var constants = { BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'], EMPTY_BUFFER: Buffer.alloc(0), GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', kForOnEventAttribute: Symbol('kIsForOnEventAttribute'), kListener: Symbol('kListener'), kStatusCode: Symbol('status-code'), kWebSocket: Symbol('websocket'), NOOP: () => {} }; var unmask$1; var mask; const { EMPTY_BUFFER: EMPTY_BUFFER$3 } = constants; const FastBuffer$2 = 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$1(list, totalLength) { if (list.length === 0) return EMPTY_BUFFER$3; 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$2(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$1(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$2(data) { toBuffer$2.readOnly = true; if (Buffer.isBuffer(data)) return data; let buf; if (data instanceof ArrayBuffer) { buf = new FastBuffer$2(data); } else if (ArrayBuffer.isView(data)) { buf = new FastBuffer$2(data.buffer, data.byteOffset, data.byteLength); } else { buf = Buffer.from(data); toBuffer$2.readOnly = false; } return buf; } bufferUtil$1.exports = { concat: concat$1, mask: _mask, toArrayBuffer: toArrayBuffer$1, toBuffer: toBuffer$2, unmask: _unmask }; /* istanbul ignore else */ if (!process.env.WS_NO_BUFFER_UTIL) { try { const bufferUtil = require('bufferutil'); mask = bufferUtil$1.exports.mask = function (source, mask, output, offset, length) { if (length < 48) _mask(source, mask, output, offset, length); else bufferUtil.mask(source, mask, output, offset, length); }; unmask$1 = bufferUtil$1.exports.unmask = function (buffer, mask) { if (buffer.length < 32) _unmask(buffer, mask); else bufferUtil.unmask(buffer, mask); }; } catch (e) { // Continue regardless of the error. } } var bufferUtilExports = bufferUtil$1.exports; const kDone = Symbol('kDone'); const kRun = Symbol('kRun'); /** * A very simple job queue with adjustable concurrency. Adapted from * https://github.com/STRML/async-limiter */ let Limiter$1 = 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]); } } }; var limiter = Limiter$1; const zlib = require$$0$4; const bufferUtil = bufferUtilExports; const Limiter = limiter; const { kStatusCode: kStatusCode$2 } = constants; const FastBuffer$1 = 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$1 = 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. */ let PerMessageDeflate$4 = 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$1]; 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$1(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); }); } }; var permessageDeflate = PerMessageDeflate$4; /** * 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$1] = new RangeError('Max payload size exceeded'); this[kError$1].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; this[kError$1][kStatusCode$2] = 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$2] = 1007; this[kCallback](err); } var validation = {exports: {}}; var isValidUTF8_1; const { isUtf8 } = require$$0$5; // // Allowed token characters: // // '!', '#', '$', '%', '&', ''', '*', '+', '-', // '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' // // tokenChars[32] === 0 // ' ' // tokenChars[33] === 1 // '!' // tokenChars[34] === 0 // '"' // ... // // prettier-ignore const tokenChars$2 = [ 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$2(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; } validation.exports = { isValidStatusCode: isValidStatusCode$2, isValidUTF8: _isValidUTF8, tokenChars: tokenChars$2 }; if (isUtf8) { isValidUTF8_1 = 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'); isValidUTF8_1 = validation.exports.isValidUTF8 = function (buf) { return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf); }; } catch (e) { // Continue regardless of the error. } } var validationExports = validation.exports; const { Writable } = require$$0$1; const PerMessageDeflate$3 = permessageDeflate; const { BINARY_TYPES: BINARY_TYPES$1, EMPTY_BUFFER: EMPTY_BUFFER$2, kStatusCode: kStatusCode$1, kWebSocket: kWebSocket$2 } = constants; const { concat, toArrayBuffer, unmask } = bufferUtilExports; const { isValidStatusCode: isValidStatusCode$1, isValidUTF8 } = validationExports; const FastBuffer = Buffer[Symbol.species]; const promise = Promise.resolve(); // // `queueMicrotask()` is not available in Node.js < 11. // const queueTask = typeof queueMicrotask === 'function' ? queueMicrotask : queueMicrotaskShim; 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 WAIT_MICROTASK = 6; /** * HyBi Receiver implementation. * * @extends Writable */ let Receiver$1 = class Receiver extends Writable { /** * Creates a Receiver instance. * * @param {Object} [options] Options object * @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._binaryType = options.binaryType || BINARY_TYPES$1[0]; this._extensions = options.extensions || {}; this._isServer = !!options.isServer; this._maxPayload = options.maxPayload | 0; this._skipUTF8Validation = !!options.skipUTF8Validation; this[kWebSocket$2] = 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._state = GET_INFO; this._loop = false; } /** * 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) { let err; this._loop = true; do { switch (this._state) { case GET_INFO: err = this.getInfo(); break; case GET_PAYLOAD_LENGTH_16: err = this.getPayloadLength16(); break; case GET_PAYLOAD_LENGTH_64: err = this.getPayloadLength64(); break; case GET_MASK: this.getMask(); break; case GET_DATA: err = this.getData(cb); break; case INFLATING: this._loop = false; return; default: // // `WAIT_MICROTASK`. // this._loop = false; queueTask(() => { this._state = GET_INFO; this.startLoop(cb); }); return; } } while (this._loop); cb(err); } /** * Reads the first two bytes of a frame. * * @return {(RangeError|undefined)} A possible error * @private */ getInfo() { if (this._bufferedBytes < 2) { this._loop = false; return; } const buf = this.consume(2); if ((buf[0] & 0x30) !== 0x00) { this._loop = false; return error( RangeError, 'RSV2 and RSV3 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_2_3' ); } const compressed = (buf[0] & 0x40) === 0x40; if (compressed && !this._extensions[PerMessageDeflate$3.extensionName]) { this._loop = false; return error( RangeError, 'RSV1 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_1' ); } this._fin = (buf[0] & 0x80) === 0x80; this._opcode = buf[0] & 0x0f; this._payloadLength = buf[1] & 0x7f; if (this._opcode === 0x00) { if (compressed) { this._loop = false; return error( RangeError, 'RSV1 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_1' ); } if (!this._fragmented) { this._loop = false; return error( RangeError, 'invalid opcode 0', true, 1002, 'WS_ERR_INVALID_OPCODE' ); } this._opcode = this._fragmented; } else if (this._opcode === 0x01 || this._opcode === 0x02) { if (this._fragmented) { this._loop = false; return error( RangeError, `invalid opcode ${this._opcode}`, true, 1002, 'WS_ERR_INVALID_OPCODE' ); } this._compressed = compressed; } else if (this._opcode > 0x07 && this._opcode < 0x0b) { if (!this._fin) { this._loop = false; return error( RangeError, 'FIN must be set', true, 1002, 'WS_ERR_EXPECTED_FIN' ); } if (compressed) { this._loop = false; return error( RangeError, 'RSV1 must be clear', true, 1002, 'WS_ERR_UNEXPECTED_RSV_1' ); } if ( this._payloadLength > 0x7d || (this._opcode === 0x08 && this._payloadLength === 1) ) { this._loop = false; return error( RangeError, `invalid payload length ${this._payloadLength}`, true, 1002, 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH' ); } } else { this._loop = false; return error( RangeError, `invalid opcode ${this._opcode}`, true, 1002, 'WS_ERR_INVALID_OPCODE' ); } if (!this._fin && !this._fragmented) this._fragmented = this._opcode; this._masked = (buf[1] & 0x80) === 0x80; if (this._isServer) { if (!this._masked) { this._loop = false; return error( RangeError, 'MASK must be set', true, 1002, 'WS_ERR_EXPECTED_MASK' ); } } else if (this._masked) { this._loop = false; return error( RangeError, 'MASK must be clear', true, 1002, 'WS_ERR_UNEXPECTED_MASK' ); } if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; else return this.haveLength(); } /** * Gets extended payload length (7+16). * * @return {(RangeError|undefined)} A possible error * @private */ getPayloadLength16() { if (this._bufferedBytes < 2) { this._loop = false; return; } this._payloadLength = this.consume(2).readUInt16BE(0); return this.haveLength(); } /** * Gets extended payload length (7+64). * * @return {(RangeError|undefined)} A possible error * @private */ getPayloadLength64() { 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) { this._loop = false; return error( RangeError, 'Unsupported WebSocket frame: payload length > 2^53 - 1', false, 1009, 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH' ); } this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); return this.haveLength(); } /** * Payload length has been read. * * @return {(RangeError|undefined)} A possible error * @private */ haveLength() { if (this._payloadLength && this._opcode < 0x08) { this._totalPayloadLength += this._payloadLength; if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { this._loop = false; return error( RangeError, 'Max payload size exceeded', false, 1009, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' ); } } 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 * @return {(Error|RangeError|undefined)} A possible error * @private */ getData(cb) { let data = EMPTY_BUFFER$2; 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) return this.controlMessage(data); 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); } return this.dataMessage(); } /** * Decompresses data. * * @param {Buffer} data Compressed data * @param {Function} cb Callback * @private */ decompress(data, cb) { const perMessageDeflate = this._extensions[PerMessageDeflate$3.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) { return cb( error( RangeError, 'Max payload size exceeded', false, 1009, 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' ) ); } this._fragments.push(buf); } const er = this.dataMessage(); if (er) return cb(er); this.startLoop(cb); }); } /** * Handles a data message. * * @return {(Error|undefined)} A possible error * @private */ dataMessage() { if (this._fin) { 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 { data = fragments; } this.emit('message', data, true); } else { const buf = concat(fragments, messageLength); if (!this._skipUTF8Validation && !isValidUTF8(buf)) { this._loop = false; return error( Error, 'invalid UTF-8 sequence', true, 1007, 'WS_ERR_INVALID_UTF8' ); } this.emit('message', buf, false); } } this._state = WAIT_MICROTASK; } /** * Handles a control message. * * @param {Buffer} data Data to handle * @return {(Error|RangeError|undefined)} A possible error * @private */ controlMessage(data) { if (this._opcode === 0x08) { this._loop = false; if (data.length === 0) { this.emit('conclude', 1005, EMPTY_BUFFER$2); this.end(); this._state = GET_INFO; } else { const code = data.readUInt16BE(0); if (!isValidStatusCode$1(code)) { return error( RangeError, `invalid status code ${code}`, true, 1002, 'WS_ERR_INVALID_CLOSE_CODE' ); } const buf = new FastBuffer( data.buffer, data.byteOffset + 2, data.length - 2 ); if (!this._skipUTF8Validation && !isValidUTF8(buf)) { return error( Error, 'invalid UTF-8 sequence', true, 1007, 'WS_ERR_INVALID_UTF8' ); } this.emit('conclude', code, buf); this.end(); this._state = GET_INFO; } } else if (this._opcode === 0x09) { this.emit('ping', data); this._state = WAIT_MICROTASK; } else { this.emit('pong', data); this._state = WAIT_MICROTASK; } } }; var receiver = Receiver$1; /** * 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 */ function error(ErrorCtor, message, prefix, statusCode, errorCode) { const err = new ErrorCtor( prefix ? `Invalid WebSocket frame: ${message}` : message ); Error.captureStackTrace(err, error); err.code = errorCode; err[kStatusCode$1] = statusCode; return err; } /** * A shim for `queueMicrotask()`. * * @param {Function} cb Callback */ function queueMicrotaskShim(cb) { promise.then(cb).catch(throwErrorNextTick); } /** * Throws an error. * * @param {Error} err The error to throw * @private */ function throwError(err) { throw err; } /** * Throws an error in the next tick. * * @param {Error} err The error to throw * @private */ function throwErrorNextTick(err) { process.nextTick(throwError, err); } /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */ const { randomFillSync } = require$$1; const PerMessageDeflate$2 = permessageDeflate; const { EMPTY_BUFFER: EMPTY_BUFFER$1 } = constants; const { isValidStatusCode } = validationExports; const { mask: applyMask, toBuffer: toBuffer$1 } = bufferUtilExports; const kByteLength = Symbol('kByteLength'); const maskBuffer = Buffer.alloc(4); /** * HyBi Sender implementation. */ let Sender$1 = 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._deflating = false; this._queue = []; } /** * 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 { randomFillSync(mask, 0, 4); } 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$1; } 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._deflating) { 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 { data = toBuffer$1(data); byteLength = data.length; readOnly = toBuffer$1.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 (this._deflating) { 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 { data = toBuffer$1(data); byteLength = data.length; readOnly = toBuffer$1.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 (this._deflating) { 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$2.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 { data = toBuffer$1(data); byteLength = data.length; readOnly = toBuffer$1.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; if (perMessageDeflate) { const opts = { [kByteLength]: byteLength, fin: options.fin, generateMask: this._generateMask, mask: options.mask, maskBuffer: this._maskBuffer, opcode, readOnly, rsv1 }; if (this._deflating) { this.enqueue([this.dispatch, data, this._compress, opts, cb]); } else { this.dispatch(data, this._compress, opts, cb); } } else { this.sendFrame( Sender.frame(data, { [kByteLength]: byteLength, fin: options.fin, generateMask: this._generateMask, mask: options.mask, maskBuffer: this._maskBuffer, opcode, readOnly, rsv1: false }), 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$2.extensionName]; this._bufferedBytes += options[kByteLength]; this._deflating = true; perMessageDeflate.compress(data, options.fin, (_, buf) => { if (this._socket.destroyed) { const err = new Error( 'The socket was closed while data was being compressed' ); if (typeof cb === 'function') cb(err); for (let i = 0; i < this._queue.length; i++) { const params = this._queue[i]; const callback = params[params.length - 1]; if (typeof callback === 'function') callback(err); } return; } this._bufferedBytes -= options[kByteLength]; this._deflating = false; options.readOnly = false; this.sendFrame(Sender.frame(buf, options), cb); this.dequeue(); }); } /** * Executes queued send operations. * * @private */ dequeue() { while (!this._deflating && 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); } } }; var sender = Sender$1; const { kForOnEventAttribute: kForOnEventAttribute$1, kListener: kListener$1 } = constants; 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$1] && listener[kListener$1] === handler && !listener[kForOnEventAttribute$1] ) { 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$1] = !!options[kForOnEventAttribute$1]; wrapper[kListener$1] = 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$1] === handler && !listener[kForOnEventAttribute$1]) { this.removeListener(type, listener); break; } } } }; var 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); } } const { tokenChars: tokenChars$1 } = validationExports; /** * 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$2(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$1[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$1[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$1[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$1[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$1[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$1(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(', '); } var extension$1 = { format: format$1, parse: parse$2 }; /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$" }] */ const EventEmitter$1 = require$$0$3; const https = require$$1$1; const http$1 = require$$2; const net = require$$3; const tls = require$$4; const { randomBytes, createHash: createHash$1 } = require$$1; const { URL: URL$1 } = require$$7; const PerMessageDeflate$1 = permessageDeflate; const Receiver = receiver; const Sender = sender; const { BINARY_TYPES, EMPTY_BUFFER, GUID: GUID$1, kForOnEventAttribute, kListener, kStatusCode, kWebSocket: kWebSocket$1, NOOP } = constants; const { EventTarget: { addEventListener, removeEventListener } } = eventTarget; const { format, parse: parse$1 } = extension$1; const { toBuffer } = bufferUtilExports; 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 */ let WebSocket$1 = class WebSocket extends EventEmitter$1 { /** * 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._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._isServer = true; } } /** * This deviates from the WHATWG interface since ws doesn't support the * required default "blob" type (instead we define a custom "nodebuffer" * type). * * @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 {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({ binaryType: this.binaryType, extensions: this._extensions, isServer: this._isServer, maxPayload: options.maxPayload, skipUTF8Validation: options.skipUTF8Validation }); this._sender = new Sender(socket, this._extensions, options.generateMask); this._receiver = receiver; this._socket = socket; receiver[kWebSocket$1] = this; socket[kWebSocket$1] = 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); // // 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$1); 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$1.extensionName]) { this._extensions[PerMessageDeflate$1.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$1(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(); } }); // // Specify a timeout for the closing handshake to complete. // this._closeTimer = setTimeout( this._socket.destroy.bind(this._socket), closeTimeout ); } /** * 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$1.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$1(this, this._req, msg); return; } if (this._socket) { this._readyState = WebSocket.CLOSING; this._socket.destroy(); } } }; /** * @constant {Number} CONNECTING * @memberof WebSocket */ Object.defineProperty(WebSocket$1, 'CONNECTING', { enumerable: true, value: readyStates.indexOf('CONNECTING') }); /** * @constant {Number} CONNECTING * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket$1.prototype, 'CONNECTING', { enumerable: true, value: readyStates.indexOf('CONNECTING') }); /** * @constant {Number} OPEN * @memberof WebSocket */ Object.defineProperty(WebSocket$1, 'OPEN', { enumerable: true, value: readyStates.indexOf('OPEN') }); /** * @constant {Number} OPEN * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket$1.prototype, 'OPEN', { enumerable: true, value: readyStates.indexOf('OPEN') }); /** * @constant {Number} CLOSING * @memberof WebSocket */ Object.defineProperty(WebSocket$1, 'CLOSING', { enumerable: true, value: readyStates.indexOf('CLOSING') }); /** * @constant {Number} CLOSING * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket$1.prototype, 'CLOSING', { enumerable: true, value: readyStates.indexOf('CLOSING') }); /** * @constant {Number} CLOSED * @memberof WebSocket */ Object.defineProperty(WebSocket$1, 'CLOSED', { enumerable: true, value: readyStates.indexOf('CLOSED') }); /** * @constant {Number} CLOSED * @memberof WebSocket.prototype */ Object.defineProperty(WebSocket$1.prototype, 'CLOSED', { enumerable: true, value: readyStates.indexOf('CLOSED') }); [ 'binaryType', 'bufferedAmount', 'extensions', 'isPaused', 'protocol', 'readyState', 'url' ].forEach((property) => { Object.defineProperty(WebSocket$1.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$1.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$1.prototype.addEventListener = addEventListener; WebSocket$1.prototype.removeEventListener = removeEventListener; var websocket = WebSocket$1; /** * 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.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 = { protocolVersion: protocolVersions[1], maxPayload: 100 * 1024 * 1024, skipUTF8Validation: false, perMessageDeflate: true, followRedirects: false, maxRedirects: 10, ...options, createConnection: undefined, socketPath: undefined, hostname: undefined, protocol: undefined, timeout: undefined, method: 'GET', host: undefined, path: undefined, port: undefined }; if (!protocolVersions.includes(opts.protocolVersion)) { throw new RangeError( `Unsupported protocol version: ${opts.protocolVersion} ` + `(supported versions: ${protocolVersions.join(', ')})` ); } let parsedUrl; if (address instanceof URL$1) { parsedUrl = address; } else { try { parsedUrl = new URL$1(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$1.request; const protocolSet = new Set(); let perMessageDeflate; 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$1( opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, false, opts.maxPayload ); opts.headers['Sec-WebSocket-Extensions'] = format({ [PerMessageDeflate$1.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$1(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$1(websocket, req, 'Maximum redirects exceeded'); return; } req.abort(); let addr; try { addr = new URL$1(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$1( 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$1.CONNECTING) return; req = websocket._req = null; if (res.headers.upgrade.toLowerCase() !== 'websocket') { abortHandshake$1(websocket, socket, 'Invalid Upgrade header'); return; } const digest = createHash$1('sha1') .update(key + GUID$1) .digest('base64'); if (res.headers['sec-websocket-accept'] !== digest) { abortHandshake$1(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$1(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$1(websocket, socket, message); return; } let extensions; try { extensions = parse$1(secWebSocketExtensions); } catch (err) { const message = 'Invalid Sec-WebSocket-Extensions header'; abortHandshake$1(websocket, socket, message); return; } const extensionNames = Object.keys(extensions); if ( extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate$1.extensionName ) { const message = 'Server indicated an extension that was not requested'; abortHandshake$1(websocket, socket, message); return; } try { perMessageDeflate.accept(extensions[PerMessageDeflate$1.extensionName]); } catch (err) { const message = 'Invalid Sec-WebSocket-Extensions header'; abortHandshake$1(websocket, socket, message); return; } websocket._extensions[PerMessageDeflate$1.extensionName] = perMessageDeflate; } websocket.setSocket(socket, head, { 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$1.CLOSING; 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$1(websocket, stream, message) { websocket._readyState = WebSocket$1.CLOSING; const err = new Error(message); Error.captureStackTrace(err, abortHandshake$1); 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 = 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$1]; websocket._closeFrameReceived = true; websocket._closeMessage = reason; websocket._closeCode = code; if (websocket._socket[kWebSocket$1] === 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$1]; 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$1]; if (websocket._socket[kWebSocket$1] !== 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]); } websocket.emit('error', err); } /** * The listener of the `Receiver` `'finish'` event. * * @private */ function receiverOnFinish() { this[kWebSocket$1].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$1].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$1]; websocket.pong(data, !websocket._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$1].emit('pong', data); } /** * Resume a readable stream * * @param {Readable} stream The readable stream * @private */ function resume(stream) { stream.resume(); } /** * The listener of the socket `'close'` event. * * @private */ function socketOnClose() { const websocket = this[kWebSocket$1]; this.removeListener('close', socketOnClose); this.removeListener('data', socketOnData); this.removeListener('end', socketOnEnd); websocket._readyState = WebSocket$1.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$1] = 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$1]._receiver.write(chunk)) { this.pause(); } } /** * The listener of the socket `'end'` event. * * @private */ function socketOnEnd() { const websocket = this[kWebSocket$1]; websocket._readyState = WebSocket$1.CLOSING; websocket._receiver.end(); this.end(); } /** * The listener of the socket `'error'` event. * * @private */ function socketOnError$1() { const websocket = this[kWebSocket$1]; this.removeListener('error', socketOnError$1); this.on('error', NOOP); if (websocket) { websocket._readyState = WebSocket$1.CLOSING; this.destroy(); } } const { tokenChars } = validationExports; /** * 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; } var subprotocol$1 = { parse }; /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */ const EventEmitter = require$$0$3; const http = require$$2; const { createHash } = require$$1; const extension = extension$1; const PerMessageDeflate = permessageDeflate; const subprotocol = subprotocol$1; const WebSocket = websocket; const { GUID, kWebSocket } = constants; 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 {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 = { 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 version = +req.headers['sec-websocket-version']; if (req.method !== 'GET') { const message = 'Invalid HTTP method'; abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); return; } if (req.headers.upgrade.toLowerCase() !== 'websocket') { const message = 'Invalid Upgrade header'; abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); return; } if (!key || !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); 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, { 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); } } var 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); } } var WebSocketServer$1 = /*@__PURE__*/getDefaultExportFromCjs(websocketServer); 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; } function setup(vitestOrWorkspace, _server) { var _a; const ctx = "ctx" in vitestOrWorkspace ? vitestOrWorkspace.ctx : vitestOrWorkspace; const wss = new WebSocketServer$1({ noServer: true }); const clients = /* @__PURE__ */ new Map(); const server = _server || ctx.server; (_a = server.httpServer) == null ? void 0 : _a.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 checkFileAccess(path) { if (!isFileServingAllowed(path, server)) throw new Error(`Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`); } function setupClient(ws) { const rpc = createBirpc( { async onUnhandledError(error, type) { ctx.state.catchError(error, type); }, async onCollected(files) { ctx.state.collectFiles(files); await ctx.report("onCollected", files); }, async onTaskUpdate(packs) { ctx.state.updateTasks(packs); await ctx.report("onTaskUpdate", packs); }, onAfterSuiteRun(meta) { var _a2; (_a2 = ctx.coverageProvider) == null ? void 0 : _a2.onAfterSuiteRun(meta); }, getFiles() { return ctx.state.getFiles(); }, getPaths() { return ctx.state.getPaths(); }, sendLog(log) { return ctx.report("onUserConsoleLog", log); }, resolveSnapshotPath(testPath) { return ctx.snapshot.resolvePath(testPath); }, resolveSnapshotRawPath(testPath, rawPath) { return ctx.snapshot.resolveRawPath(testPath, rawPath); }, async readSnapshotFile(snapshotPath) { checkFileAccess(snapshotPath); if (!existsSync(snapshotPath)) return null; return promises$1.readFile(snapshotPath, "utf-8"); }, async readTestFile(id) { if (!ctx.state.filesMap.has(id) || !existsSync(id)) return null; return promises$1.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$1.writeFile(id, content, "utf-8"); }, async saveSnapshotFile(id, content) { checkFileAccess(id); await promises$1.mkdir(dirname(id), { recursive: true }); return promises$1.writeFile(id, content, "utf-8"); }, async removeSnapshotFile(id) { checkFileAccess(id); if (!existsSync(id)) throw new Error(`Snapshot file "${id}" does not exist.`); return promises$1.unlink(id); }, snapshotSaved(snapshot) { ctx.snapshot.add(snapshot); }, async rerun(files) { await ctx.rerunFiles(files); }, getConfig() { return vitestOrWorkspace.config; }, async getBrowserFileSourceMap(id) { var _a2, _b; if (!("ctx" in vitestOrWorkspace)) return void 0; const mod = (_a2 = vitestOrWorkspace.browser) == null ? void 0 : _a2.moduleGraph.getModuleById(id); return (_b = mod == null ? void 0 : mod.transformResult) == null ? void 0 : _b.map; }, async getTransformResult(id) { const result = await ctx.vitenode.transformRequest(id); if (result) { try { result.source = result.source || await promises$1.readFile(id, "utf-8"); } catch { } return result; } }, async getModuleGraph(id) { return getModuleGraph(ctx, id); }, updateSnapshot(file) { if (!file) return ctx.updateSnapshot(); return ctx.updateSnapshot([file.filepath]); }, onCancel(reason) { ctx.cancelCurrentRun(reason); }, debug(...args) { ctx.logger.console.debug(...args); }, getCountOfFailedTests() { return ctx.state.getCountOfFailedTests(); }, getUnhandledErrors() { return ctx.state.getUnhandledErrors(); }, // TODO: have a separate websocket conection for private browser API getBrowserFiles() { var _a2; if (!("ctx" in vitestOrWorkspace)) throw new Error("`getBrowserTestFiles` is only available in the browser API"); return ((_a2 = vitestOrWorkspace.browserState) == null ? void 0 : _a2.files) ?? []; }, finishBrowserTests() { var _a2; if (!("ctx" in vitestOrWorkspace)) throw new Error("`finishBrowserTests` is only available in the browser API"); return (_a2 = vitestOrWorkspace.browserState) == null ? void 0 : _a2.resolve(); }, getProvidedContext() { return "ctx" in vitestOrWorkspace ? vitestOrWorkspace.getProvidedContext() : {}; }, async getTestFiles() { const spec = await ctx.globTestFiles(); return spec.map(([project, file]) => [project.getName(), file]); } }, { post: (msg) => ws.send(msg), on: (fn) => ws.on("message", fn), eventNames: ["onUserConsoleLog", "onFinished", "onFinishedReportCoverage", "onCollected", "onCancel", "onTaskUpdate"], serialize: (data) => stringify(data, stringifyReplace), deserialize: parse$3, onTimeoutError(functionName) { throw new Error(`[vitest-api]: Timeout calling "${functionName}"`); } } ); ctx.onCancel((reason) => rpc.onCancel(reason)); 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) => { var _a, _b, _c; (_c = (_b = (_a = client.onCollected) == null ? void 0 : _a.call(client, files)) == null ? void 0 : _b.catch) == null ? void 0 : _c.call(_b, noop$2); }); } async onTaskUpdate(packs) { if (this.clients.size === 0) return; packs.forEach(([taskId, result]) => { var _a; const project = this.ctx.getProjectByTaskId(taskId); const parserOptions = { getSourceMap: (file) => project.getBrowserSourceMapModuleById(file) }; (_a = result == null ? void 0 : result.errors) == null ? void 0 : _a.forEach((error) => { if (!isPrimitive(error)) error.stacks = parseErrorStacktrace(error, parserOptions); }); }); this.clients.forEach((client) => { var _a, _b, _c; (_c = (_b = (_a = client.onTaskUpdate) == null ? void 0 : _a.call(client, packs)) == null ? void 0 : _b.catch) == null ? void 0 : _c.call(_b, noop$2); }); } onFinished(files, errors) { this.clients.forEach((client) => { var _a, _b, _c; (_c = (_b = (_a = client.onFinished) == null ? void 0 : _a.call(client, files, errors)) == null ? void 0 : _b.catch) == null ? void 0 : _c.call(_b, noop$2); }); } onFinishedReportCoverage() { this.clients.forEach((client) => { var _a, _b, _c; (_c = (_b = (_a = client.onFinishedReportCoverage) == null ? void 0 : _a.call(client)) == null ? void 0 : _b.catch) == null ? void 0 : _c.call(_b, noop$2); }); } onUserConsoleLog(log) { this.clients.forEach((client) => { var _a, _b, _c; (_c = (_b = (_a = client.onUserConsoleLog) == null ? void 0 : _a.call(client, log)) == null ? void 0 : _b.catch) == null ? void 0 : _c.call(_b, noop$2); }); } } var setup$1 = /*#__PURE__*/Object.freeze({ __proto__: null, WebSocketReporter: WebSocketReporter, setup: setup }); const envsOrder = [ "node", "jsdom", "happy-dom", "edge-runtime" ]; function getTransformMode(patterns, filename) { if (patterns.web && mm.isMatch(filename, patterns.web)) return "web"; if (patterns.ssr && mm.isMatch(filename, patterns.ssr)) return "ssr"; return void 0; } async function groupFilesByEnv(files) { const filesWithEnv = await Promise.all(files.map(async ([project, file]) => { var _a, _b; const code = await promises$1.readFile(file, "utf-8"); let env = (_a = code.match(/@(?:vitest|jest)-environment\s+?([\w-]+)\b/)) == null ? void 0 : _a[1]; if (!env) { for (const [glob, target] of project.config.environmentMatchGlobs || []) { if (mm.isMatch(file, glob, { cwd: project.config.root })) { env = target; break; } } } env || (env = project.config.environment || "node"); const transformMode = getTransformMode(project.config.testTransformMode, file); const envOptions = JSON.parse(((_b = code.match(/@(?:vitest|jest)-environment-options\s+?(.+)/)) == null ? void 0 : _b[1]) || "null"); const envKey = env === "happy-dom" ? "happyDOM" : env; const environment = { name: env, transformMode, options: envOptions ? { [envKey]: envOptions } : null }; return { file, project, environment }; })); return groupBy(filesWithEnv, ({ environment }) => environment.name); } const created = /* @__PURE__ */ new Set(); const promises = /* @__PURE__ */ new Map(); function createMethodsRPC(project) { const ctx = project.ctx; return { snapshotSaved(snapshot) { ctx.snapshot.add(snapshot); }, resolveSnapshotPath(testPath) { return ctx.snapshot.resolvePath(testPath); }, async getSourceMap(id, force) { if (force) { const mod = project.server.moduleGraph.getModuleById(id); if (mod) project.server.moduleGraph.invalidateModule(mod); } const r = await project.vitenode.transformRequest(id); return r == null ? void 0 : r.map; }, async fetch(id, transformMode) { const result = await project.vitenode.fetchResult(id, transformMode); const code = result.code; if (result.externalize) return result; if ("id" in result && typeof result.id === "string") return { id: result.id }; if (code == null) throw new Error(`Failed to fetch module ${id}`); const dir = join(project.tmpDir, transformMode); const name = createHash$2("sha1").update(id).digest("hex"); const tmp = join(dir, name); if (promises.has(tmp)) { await promises.get(tmp); return { id: tmp }; } if (!created.has(dir)) { await mkdir(dir, { recursive: true }); created.add(dir); } promises.set(tmp, writeFile(tmp, code, "utf-8").finally(() => promises.delete(tmp))); await promises.get(tmp); Object.assign(result, { id: tmp }); return { id: tmp }; }, resolveId(id, importer, transformMode) { return project.vitenode.resolveId(id, importer, transformMode); }, transform(id, environment) { return project.vitenode.transformModule(id, environment); }, onPathsCollected(paths) { ctx.state.collectPaths(paths); return ctx.report("onPathsCollected", paths); }, onCollected(files) { ctx.state.collectFiles(files); return ctx.report("onCollected", files); }, onAfterSuiteRun(meta) { var _a; (_a = ctx.coverageProvider) == null ? void 0 : _a.onAfterSuiteRun(meta); }, onTaskUpdate(packs) { ctx.state.updateTasks(packs); return ctx.report("onTaskUpdate", packs); }, onUserConsoleLog(log) { ctx.state.updateUserLog(log); ctx.report("onUserConsoleLog", log); }, onUnhandledError(err, type) { ctx.state.catchError(err, type); }, onFinished(files) { return ctx.report("onFinished", files, ctx.state.getUnhandledErrors()); }, onCancel(reason) { ctx.cancelCurrentRun(reason); }, getCountOfFailedTests() { return ctx.state.getCountOfFailedTests(); } }; } function createChildProcessChannel$1(project) { const emitter = new EventEmitter$2(); const cleanup = () => emitter.removeAllListeners(); const events = { message: "message", response: "response" }; const channel = { onMessage: (callback) => emitter.on(events.message, callback), postMessage: (message) => emitter.emit(events.response, message) }; const rpc = createBirpc( createMethodsRPC(project), { eventNames: ["onCancel"], serialize: v8.serialize, deserialize: (v) => v8.deserialize(Buffer.from(v)), post(v) { emitter.emit(events.message, v); }, on(fn) { emitter.on(events.response, fn); }, onTimeoutError(functionName) { throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`); } } ); project.ctx.onCancel((reason) => rpc.onCancel(reason)); return { channel, cleanup }; } function createForksPool(ctx, { execArgv, env }) { var _a; const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length; const threadsCount = ctx.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1); const poolOptions = ((_a = ctx.config.poolOptions) == null ? void 0 : _a.forks) ?? {}; const maxThreads = poolOptions.maxForks ?? ctx.config.maxWorkers ?? threadsCount; const minThreads = poolOptions.minForks ?? ctx.config.minWorkers ?? threadsCount; const worker = resolve(ctx.distPath, "workers/forks.js"); const options = { runtime: "child_process", filename: resolve(ctx.distPath, "worker.js"), maxThreads, minThreads, env, execArgv: [ ...poolOptions.execArgv ?? [], ...execArgv ], terminateTimeout: ctx.config.teardownTimeout, concurrentTasksPerWorker: 1 }; const isolated = poolOptions.isolate ?? true; if (isolated) options.isolateWorkers = true; if (poolOptions.singleFork || !ctx.config.fileParallelism) { options.maxThreads = 1; options.minThreads = 1; } const pool = new Tinypool(options); const runWithFiles = (name) => { let id = 0; async function runFiles(project, config, files, environment, invalidates = []) { ctx.state.clearFiles(project, files); const { channel, cleanup } = createChildProcessChannel$1(project); const workerId = ++id; const data = { pool: "forks", worker, config, files, invalidates, environment, workerId, projectName: project.getName(), providedContext: project.getProvidedContext() }; try { await pool.run(data, { name, channel }); } catch (error) { if (error instanceof Error && /Failed to terminate worker/.test(error.message)) ctx.state.addProcessTimeoutCause(`Failed to terminate worker while running ${files.join(", ")}.`); else if (ctx.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) ctx.state.cancelFiles(files, ctx.config.root, project.config.name); else throw error; } finally { cleanup(); } } return async (specs, invalidates) => { ctx.onCancel(() => pool.cancelPendingTasks()); const configs = /* @__PURE__ */ new Map(); const getConfig = (project) => { if (configs.has(project)) return configs.get(project); const _config = project.getSerializableConfig(); const config = wrapSerializableConfig(_config); configs.set(project, config); return config; }; const workspaceMap = /* @__PURE__ */ new Map(); for (const [project, file] of specs) { const workspaceFiles = workspaceMap.get(file) ?? []; workspaceFiles.push(project); workspaceMap.set(file, workspaceFiles); } const singleFork = specs.filter(([project]) => { var _a2, _b; return (_b = (_a2 = project.config.poolOptions) == null ? void 0 : _a2.forks) == null ? void 0 : _b.singleFork; }); const multipleForks = specs.filter(([project]) => { var _a2, _b; return !((_b = (_a2 = project.config.poolOptions) == null ? void 0 : _a2.forks) == null ? void 0 : _b.singleFork); }); if (multipleForks.length) { const filesByEnv = await groupFilesByEnv(multipleForks); const files = Object.values(filesByEnv).flat(); const results = []; if (isolated) { results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))); } else { const grouped = groupBy(files, ({ project, environment }) => project.getName() + environment.name + JSON.stringify(environment.options)); for (const group of Object.values(grouped)) { results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))); await new Promise((resolve2) => pool.queueSize === 0 ? resolve2() : pool.once("drain", resolve2)); await pool.recycleWorkers(); } } const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason); if (errors.length > 0) throw new AggregateError(errors, "Errors occurred while running tests. For more information, see serialized error."); } if (singleFork.length) { const filesByEnv = await groupFilesByEnv(singleFork); const envs = envsOrder.concat( Object.keys(filesByEnv).filter((env2) => !envsOrder.includes(env2)) ); for (const env2 of envs) { const files = filesByEnv[env2]; if (!(files == null ? void 0 : files.length)) continue; const filesByOptions = groupBy(files, ({ project, environment }) => project.getName() + JSON.stringify(environment.options)); for (const files2 of Object.values(filesByOptions)) { await pool.recycleWorkers(); const filenames = files2.map((f) => f.file); await runFiles(files2[0].project, getConfig(files2[0].project), filenames, files2[0].environment, invalidates); } } } }; }; return { name: "forks", runTests: runWithFiles("run"), close: () => pool.destroy() }; } function createWorkerChannel$1(project) { const channel = new MessageChannel(); const port = channel.port2; const workerPort = channel.port1; const rpc = createBirpc( createMethodsRPC(project), { eventNames: ["onCancel"], post(v) { port.postMessage(v); }, on(fn) { port.on("message", fn); }, onTimeoutError(functionName) { throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`); } } ); project.ctx.onCancel((reason) => rpc.onCancel(reason)); return { workerPort, port }; } function createThreadsPool(ctx, { execArgv, env }) { var _a; const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length; const threadsCount = ctx.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1); const poolOptions = ((_a = ctx.config.poolOptions) == null ? void 0 : _a.threads) ?? {}; const maxThreads = poolOptions.maxThreads ?? ctx.config.maxWorkers ?? threadsCount; const minThreads = poolOptions.minThreads ?? ctx.config.minWorkers ?? threadsCount; const worker = resolve(ctx.distPath, "workers/threads.js"); const options = { filename: resolve(ctx.distPath, "worker.js"), // TODO: investigate further // It seems atomics introduced V8 Fatal Error https://github.com/vitest-dev/vitest/issues/1191 useAtomics: poolOptions.useAtomics ?? false, maxThreads, minThreads, env, execArgv: [ ...poolOptions.execArgv ?? [], ...execArgv ], terminateTimeout: ctx.config.teardownTimeout, concurrentTasksPerWorker: 1 }; const isolated = poolOptions.isolate ?? true; if (isolated) options.isolateWorkers = true; if (poolOptions.singleThread || !ctx.config.fileParallelism) { options.maxThreads = 1; options.minThreads = 1; } const pool = new Tinypool$1(options); const runWithFiles = (name) => { let id = 0; async function runFiles(project, config, files, environment, invalidates = []) { ctx.state.clearFiles(project, files); const { workerPort, port } = createWorkerChannel$1(project); const workerId = ++id; const data = { pool: "threads", worker, port: workerPort, config, files, invalidates, environment, workerId, projectName: project.getName(), providedContext: project.getProvidedContext() }; try { await pool.run(data, { transferList: [workerPort], name }); } catch (error) { if (error instanceof Error && /Failed to terminate worker/.test(error.message)) ctx.state.addProcessTimeoutCause(`Failed to terminate worker while running ${files.join(", ")}. See https://vitest.dev/guide/common-errors.html#failed-to-terminate-worker for troubleshooting.`); else if (ctx.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) ctx.state.cancelFiles(files, ctx.config.root, project.config.name); else throw error; } finally { port.close(); workerPort.close(); } } return async (specs, invalidates) => { ctx.onCancel(() => pool.cancelPendingTasks()); const configs = /* @__PURE__ */ new Map(); const getConfig = (project) => { if (configs.has(project)) return configs.get(project); const config = project.getSerializableConfig(); configs.set(project, config); return config; }; const workspaceMap = /* @__PURE__ */ new Map(); for (const [project, file] of specs) { const workspaceFiles = workspaceMap.get(file) ?? []; workspaceFiles.push(project); workspaceMap.set(file, workspaceFiles); } const singleThreads = specs.filter(([project]) => { var _a2, _b; return (_b = (_a2 = project.config.poolOptions) == null ? void 0 : _a2.threads) == null ? void 0 : _b.singleThread; }); const multipleThreads = specs.filter(([project]) => { var _a2, _b; return !((_b = (_a2 = project.config.poolOptions) == null ? void 0 : _a2.threads) == null ? void 0 : _b.singleThread); }); if (multipleThreads.length) { const filesByEnv = await groupFilesByEnv(multipleThreads); const files = Object.values(filesByEnv).flat(); const results = []; if (isolated) { results.push(...await Promise.allSettled(files.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))); } else { const grouped = groupBy(files, ({ project, environment }) => project.getName() + environment.name + JSON.stringify(environment.options)); for (const group of Object.values(grouped)) { results.push(...await Promise.allSettled(group.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates)))); await new Promise((resolve2) => pool.queueSize === 0 ? resolve2() : pool.once("drain", resolve2)); await pool.recycleWorkers(); } } const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason); if (errors.length > 0) throw new AggregateErrorPonyfill(errors, "Errors occurred while running tests. For more information, see serialized error."); } if (singleThreads.length) { const filesByEnv = await groupFilesByEnv(singleThreads); const envs = envsOrder.concat( Object.keys(filesByEnv).filter((env2) => !envsOrder.includes(env2)) ); for (const env2 of envs) { const files = filesByEnv[env2]; if (!(files == null ? void 0 : files.length)) continue; const filesByOptions = groupBy(files, ({ project, environment }) => project.getName() + JSON.stringify(environment.options)); for (const files2 of Object.values(filesByOptions)) { await pool.recycleWorkers(); const filenames = files2.map((f) => f.file); await runFiles(files2[0].project, getConfig(files2[0].project), filenames, files2[0].environment, invalidates); } } } }; }; return { name: "threads", runTests: runWithFiles("run"), close: () => pool.destroy() }; } function createBrowserPool(ctx) { const providers = /* @__PURE__ */ new Set(); const waitForTests = async (project, files) => { var _a; const defer = createDefer(); (_a = project.browserState) == null ? void 0 : _a.resolve(); project.browserState = { files, resolve: () => { defer.resolve(); project.browserState = void 0; }, reject: defer.reject }; return await defer; }; const runTests = async (project, files) => { var _a; ctx.state.clearFiles(project, files); const provider = project.browserProvider; providers.add(provider); const resolvedUrls = (_a = project.browser) == null ? void 0 : _a.resolvedUrls; const origin = (resolvedUrls == null ? void 0 : resolvedUrls.local[0]) ?? (resolvedUrls == null ? void 0 : resolvedUrls.network[0]); if (!origin) throw new Error(`Can't find browser origin URL for project "${project.config.name}"`); const promise = waitForTests(project, files); await provider.openPage(new URL("/", origin).toString()); await promise; }; const runWorkspaceTests = async (specs) => { const groupedFiles = /* @__PURE__ */ new Map(); for (const [project, file] of specs) { const files = groupedFiles.get(project) || []; files.push(file); groupedFiles.set(project, files); } for (const [project, files] of groupedFiles.entries()) await runTests(project, files); }; return { name: "browser", async close() { await Promise.all([...providers].map((provider) => provider.close())); providers.clear(); }, runTests: runWorkspaceTests }; } function getDefaultThreadsCount(config) { const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length; return config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1); } function getWorkerMemoryLimit(config) { var _a, _b, _c, _d; const memoryLimit = (_b = (_a = config.poolOptions) == null ? void 0 : _a.vmThreads) == null ? void 0 : _b.memoryLimit; if (memoryLimit) return memoryLimit; return 1 / (((_d = (_c = config.poolOptions) == null ? void 0 : _c.vmThreads) == null ? void 0 : _d.maxThreads) ?? getDefaultThreadsCount(config)); } function stringToBytes(input, percentageReference) { if (input === null || input === void 0) return input; if (typeof input === "string") { if (Number.isNaN(Number.parseFloat(input.slice(-1)))) { let [, numericString, trailingChars] = input.match(/(.*?)([^0-9.-]+)$/i) || []; if (trailingChars && numericString) { const numericValue = Number.parseFloat(numericString); trailingChars = trailingChars.toLowerCase(); switch (trailingChars) { case "%": input = numericValue / 100; break; case "kb": case "k": return numericValue * 1e3; case "kib": return numericValue * 1024; case "mb": case "m": return numericValue * 1e3 * 1e3; case "mib": return numericValue * 1024 * 1024; case "gb": case "g": return numericValue * 1e3 * 1e3 * 1e3; case "gib": return numericValue * 1024 * 1024 * 1024; } } } else { input = Number.parseFloat(input); } } if (typeof input === "number") { if (input <= 1 && input > 0) { if (percentageReference) { return Math.floor(input * percentageReference); } else { throw new Error( "For a percentage based memory limit a percentageReference must be supplied" ); } } else if (input > 1) { return Math.floor(input); } else { throw new Error('Unexpected numerical input for "memoryLimit"'); } } return null; } const suppressWarningsPath$1 = resolve(rootDir, "./suppress-warnings.cjs"); function createWorkerChannel(project) { const channel = new MessageChannel(); const port = channel.port2; const workerPort = channel.port1; const rpc = createBirpc( createMethodsRPC(project), { eventNames: ["onCancel"], post(v) { port.postMessage(v); }, on(fn) { port.on("message", fn); }, onTimeoutError(functionName) { throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`); } } ); project.ctx.onCancel((reason) => rpc.onCancel(reason)); return { workerPort, port }; } function createVmThreadsPool(ctx, { execArgv, env }) { var _a; const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length; const threadsCount = ctx.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1); const poolOptions = ((_a = ctx.config.poolOptions) == null ? void 0 : _a.vmThreads) ?? {}; const maxThreads = poolOptions.maxThreads ?? ctx.config.maxWorkers ?? threadsCount; const minThreads = poolOptions.minThreads ?? ctx.config.minWorkers ?? threadsCount; const worker = resolve(ctx.distPath, "workers/vmThreads.js"); const options = { filename: resolve(ctx.distPath, "worker.js"), // TODO: investigate further // It seems atomics introduced V8 Fatal Error https://github.com/vitest-dev/vitest/issues/1191 useAtomics: poolOptions.useAtomics ?? false, maxThreads, minThreads, env, execArgv: [ "--experimental-import-meta-resolve", "--experimental-vm-modules", "--require", suppressWarningsPath$1, ...poolOptions.execArgv ?? [], ...execArgv ], terminateTimeout: ctx.config.teardownTimeout, concurrentTasksPerWorker: 1, maxMemoryLimitBeforeRecycle: getMemoryLimit$1(ctx.config) || void 0 }; if (poolOptions.singleThread || !ctx.config.fileParallelism) { options.maxThreads = 1; options.minThreads = 1; } const pool = new Tinypool$1(options); const runWithFiles = (name) => { let id = 0; async function runFiles(project, config, files, environment, invalidates = []) { ctx.state.clearFiles(project, files); const { workerPort, port } = createWorkerChannel(project); const workerId = ++id; const data = { pool: "vmThreads", worker, port: workerPort, config, files, invalidates, environment, workerId, projectName: project.getName(), providedContext: project.getProvidedContext() }; try { await pool.run(data, { transferList: [workerPort], name }); } catch (error) { if (error instanceof Error && /Failed to terminate worker/.test(error.message)) ctx.state.addProcessTimeoutCause(`Failed to terminate worker while running ${files.join(", ")}. See https://vitest.dev/guide/common-errors.html#failed-to-terminate-worker for troubleshooting.`); else if (ctx.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) ctx.state.cancelFiles(files, ctx.config.root, project.config.name); else throw error; } finally { port.close(); workerPort.close(); } } return async (specs, invalidates) => { ctx.onCancel(() => pool.cancelPendingTasks()); const configs = /* @__PURE__ */ new Map(); const getConfig = (project) => { if (configs.has(project)) return configs.get(project); const config = project.getSerializableConfig(); configs.set(project, config); return config; }; const filesByEnv = await groupFilesByEnv(specs); const promises = Object.values(filesByEnv).flat(); const results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))); const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason); if (errors.length > 0) throw new AggregateErrorPonyfill(errors, "Errors occurred while running tests. For more information, see serialized error."); }; }; return { name: "vmThreads", runTests: runWithFiles("run"), close: () => pool.destroy() }; } function getMemoryLimit$1(config) { const memory = nodeos.totalmem(); const limit = getWorkerMemoryLimit(config); if (typeof memory === "number") { return stringToBytes( limit, config.watch ? memory / 2 : memory ); } if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit); return null; } function createTypecheckPool(ctx) { const promisesMap = /* @__PURE__ */ new WeakMap(); const rerunTriggered = /* @__PURE__ */ new WeakMap(); async function onParseEnd(project, { files, sourceErrors }) { var _a; const checker = project.typechecker; await ctx.report("onTaskUpdate", checker.getTestPacks()); if (!project.config.typecheck.ignoreSourceErrors) sourceErrors.forEach((error) => ctx.state.catchError(error, "Unhandled Source Error")); const processError = !hasFailed(files) && !sourceErrors.length && checker.getExitCode(); if (processError) { const error = new Error(checker.getOutput()); error.stack = ""; ctx.state.catchError(error, "Typecheck Error"); } (_a = promisesMap.get(project)) == null ? void 0 : _a.resolve(); rerunTriggered.set(project, false); if (ctx.config.watch && !ctx.runningPromise) { await ctx.report("onFinished", files); await ctx.report("onWatcherStart", files, [ ...project.config.typecheck.ignoreSourceErrors ? [] : sourceErrors, ...ctx.state.getUnhandledErrors() ]); } } async function createWorkspaceTypechecker(project, files) { const checker = project.typechecker ?? new Typechecker(project); if (project.typechecker) return checker; project.typechecker = checker; checker.setFiles(files); checker.onParseStart(async () => { ctx.state.collectFiles(checker.getTestFiles()); await ctx.report("onCollected"); }); checker.onParseEnd((result) => onParseEnd(project, result)); checker.onWatcherRerun(async () => { rerunTriggered.set(project, true); if (!ctx.runningPromise) { ctx.state.clearErrors(); await ctx.report("onWatcherRerun", files, "File change detected. Triggering rerun."); } await checker.collectTests(); ctx.state.collectFiles(checker.getTestFiles()); await ctx.report("onTaskUpdate", checker.getTestPacks()); await ctx.report("onCollected"); }); await checker.prepare(); await checker.collectTests(); checker.start(); return checker; } async function runTests(specs) { const specsByProject = groupBy(specs, ([project]) => project.getName()); const promises = []; for (const name in specsByProject) { const project = specsByProject[name][0][0]; const files = specsByProject[name].map(([_, file]) => file); const promise = createDefer(); const _p = new Promise((resolve) => { const _i = setInterval(() => { if (!project.typechecker || rerunTriggered.get(project)) { resolve(true); clearInterval(_i); } }); setTimeout(() => { resolve(false); clearInterval(_i); }, 500).unref(); }); const triggered = await _p; if (project.typechecker && !triggered) { ctx.state.collectFiles(project.typechecker.getTestFiles()); await ctx.report("onCollected"); await onParseEnd(project, project.typechecker.getResult()); continue; } promises.push(promise); promisesMap.set(project, promise); createWorkspaceTypechecker(project, files); } await Promise.all(promises); } return { name: "typescript", runTests, async close() { const promises = ctx.projects.map((project) => { var _a; return (_a = project.typechecker) == null ? void 0 : _a.stop(); }); await Promise.all(promises); } }; } const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs"); function createChildProcessChannel(project) { const emitter = new EventEmitter$2(); const cleanup = () => emitter.removeAllListeners(); const events = { message: "message", response: "response" }; const channel = { onMessage: (callback) => emitter.on(events.message, callback), postMessage: (message) => emitter.emit(events.response, message) }; const rpc = createBirpc( createMethodsRPC(project), { eventNames: ["onCancel"], serialize: v8.serialize, deserialize: (v) => v8.deserialize(Buffer.from(v)), post(v) { emitter.emit(events.message, v); }, on(fn) { emitter.on(events.response, fn); }, onTimeoutError(functionName) { throw new Error(`[vitest-pool]: Timeout calling "${functionName}"`); } } ); project.ctx.onCancel((reason) => rpc.onCancel(reason)); return { channel, cleanup }; } function createVmForksPool(ctx, { execArgv, env }) { var _a; const numCpus = typeof nodeos.availableParallelism === "function" ? nodeos.availableParallelism() : nodeos.cpus().length; const threadsCount = ctx.config.watch ? Math.max(Math.floor(numCpus / 2), 1) : Math.max(numCpus - 1, 1); const poolOptions = ((_a = ctx.config.poolOptions) == null ? void 0 : _a.vmForks) ?? {}; const maxThreads = poolOptions.maxForks ?? ctx.config.maxWorkers ?? threadsCount; const minThreads = poolOptions.maxForks ?? ctx.config.minWorkers ?? threadsCount; const worker = resolve(ctx.distPath, "workers/vmForks.js"); const options = { runtime: "child_process", filename: resolve(ctx.distPath, "worker.js"), maxThreads, minThreads, env, execArgv: [ "--experimental-import-meta-resolve", "--experimental-vm-modules", "--require", suppressWarningsPath, ...poolOptions.execArgv ?? [], ...execArgv ], terminateTimeout: ctx.config.teardownTimeout, concurrentTasksPerWorker: 1, maxMemoryLimitBeforeRecycle: getMemoryLimit(ctx.config) || void 0 }; if (poolOptions.singleFork || !ctx.config.fileParallelism) { options.maxThreads = 1; options.minThreads = 1; } const pool = new Tinypool$1(options); const runWithFiles = (name) => { let id = 0; async function runFiles(project, config, files, environment, invalidates = []) { ctx.state.clearFiles(project, files); const { channel, cleanup } = createChildProcessChannel(project); const workerId = ++id; const data = { pool: "forks", worker, config, files, invalidates, environment, workerId, projectName: project.getName(), providedContext: project.getProvidedContext() }; try { await pool.run(data, { name, channel }); } catch (error) { if (error instanceof Error && /Failed to terminate worker/.test(error.message)) ctx.state.addProcessTimeoutCause(`Failed to terminate worker while running ${files.join(", ")}.`); else if (ctx.isCancelling && error instanceof Error && /The task has been cancelled/.test(error.message)) ctx.state.cancelFiles(files, ctx.config.root, project.config.name); else throw error; } finally { cleanup(); } } return async (specs, invalidates) => { ctx.onCancel(() => pool.cancelPendingTasks()); const configs = /* @__PURE__ */ new Map(); const getConfig = (project) => { if (configs.has(project)) return configs.get(project); const _config = project.getSerializableConfig(); const config = wrapSerializableConfig(_config); configs.set(project, config); return config; }; const filesByEnv = await groupFilesByEnv(specs); const promises = Object.values(filesByEnv).flat(); const results = await Promise.allSettled(promises.map(({ file, environment, project }) => runFiles(project, getConfig(project), [file], environment, invalidates))); const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason); if (errors.length > 0) throw new AggregateErrorPonyfill(errors, "Errors occurred while running tests. For more information, see serialized error."); }; }; return { name: "vmForks", runTests: runWithFiles("run"), close: () => pool.destroy() }; } function getMemoryLimit(config) { const memory = nodeos.totalmem(); const limit = getWorkerMemoryLimit(config); if (typeof memory === "number") { return stringToBytes( limit, config.watch ? memory / 2 : memory ); } if (typeof limit === "number" && limit > 1 || typeof limit === "string" && limit.at(-1) !== "%") return stringToBytes(limit); return null; } const builtinPools = ["forks", "threads", "browser", "vmThreads", "vmForks", "typescript"]; function createPool(ctx) { const pools = { forks: null, threads: null, browser: null, vmThreads: null, vmForks: null, typescript: null }; function getDefaultPoolName(project, file) { if (project.config.typecheck.enabled) { for (const glob of project.config.typecheck.include) { if (mm.isMatch(file, glob, { cwd: project.config.root })) return "typescript"; } } if (project.config.browser.enabled) return "browser"; return project.config.pool; } function getPoolName([project, file]) { for (const [glob, pool] of project.config.poolMatchGlobs) { if (pool === "browser") throw new Error('Since Vitest 0.31.0 "browser" pool is not supported in "poolMatchGlobs". You can create a workspace to run some of your tests in browser in parallel. Read more: https://vitest.dev/guide/workspace'); if (mm.isMatch(file, glob, { cwd: project.config.root })) return pool; } return getDefaultPoolName(project, file); } const potentialConditions = /* @__PURE__ */ new Set(["production", "development", ...ctx.server.config.resolve.conditions]); const conditions = [...potentialConditions].filter((condition) => { if (condition === "production") return ctx.server.config.isProduction; if (condition === "development") return !ctx.server.config.isProduction; return true; }).flatMap((c) => ["--conditions", c]); const execArgv = process.execArgv.filter( (execArg) => execArg.startsWith("--cpu-prof") || execArg.startsWith("--heap-prof") || execArg.startsWith("--diagnostic-dir") ); async function runTests(files, invalidate) { const options = { execArgv: [ ...execArgv, ...conditions ], env: { TEST: "true", VITEST: "true", NODE_ENV: process.env.NODE_ENV || "test", VITEST_MODE: ctx.config.watch ? "WATCH" : "RUN", ...process.env, ...ctx.config.env } }; if (isWindows) { for (const name in options.env) options.env[name.toUpperCase()] = options.env[name]; } const customPools = /* @__PURE__ */ new Map(); async function resolveCustomPool(filepath) { if (customPools.has(filepath)) return customPools.get(filepath); const pool = await ctx.runner.executeId(filepath); if (typeof pool.default !== "function") throw new Error(`Custom pool "${filepath}" must export a function as default export`); const poolInstance = await pool.default(ctx, options); if (typeof (poolInstance == null ? void 0 : poolInstance.name) !== "string") throw new Error(`Custom pool "${filepath}" should return an object with "name" property`); if (typeof (poolInstance == null ? void 0 : poolInstance.runTests) !== "function") throw new Error(`Custom pool "${filepath}" should return an object with "runTests" method`); customPools.set(filepath, poolInstance); return poolInstance; } const filesByPool = { forks: [], threads: [], browser: [], vmThreads: [], vmForks: [], typescript: [] }; const factories = { browser: () => createBrowserPool(ctx), vmThreads: () => createVmThreadsPool(ctx, options), threads: () => createThreadsPool(ctx, options), forks: () => createForksPool(ctx, options), vmForks: () => createVmForksPool(ctx, options), typescript: () => createTypecheckPool(ctx) }; for (const spec of files) { const pool = getPoolName(spec); filesByPool[pool] ?? (filesByPool[pool] = []); filesByPool[pool].push(spec); } const Sequencer = ctx.config.sequence.sequencer; const sequencer = new Sequencer(ctx); async function sortSpecs(specs) { if (ctx.config.shard) specs = await sequencer.shard(specs); return sequencer.sort(specs); } await Promise.all(Object.entries(filesByPool).map(async (entry) => { var _a; const [pool, files2] = entry; if (!files2.length) return null; const specs = await sortSpecs(files2); if (pool in factories) { const factory = factories[pool]; pools[pool] ?? (pools[pool] = factory()); return pools[pool].runTests(specs, invalidate); } const poolHandler = await resolveCustomPool(pool); pools[_a = poolHandler.name] ?? (pools[_a] = poolHandler); return poolHandler.runTests(specs, invalidate); })); } return { name: "default", runTests, async close() { await Promise.all(Object.values(pools).map((p) => { var _a; return (_a = p == null ? void 0 : p.close) == null ? void 0 : _a.call(p); })); } }; } 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); 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(); 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 ?? (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); } getFiles(keys) { if (keys) return keys.map((key) => this.filesMap.get(key)).filter(Boolean).flat(); return Array.from(this.filesMap.values()).flat(); } getFilepaths() { return Array.from(this.filesMap.keys()); } getFailedFilepaths() { return this.getFiles().filter((i) => { var _a; return ((_a = i.result) == null ? void 0 : _a.state) === "fail"; }).map((i) => i.filepath); } collectPaths(paths = []) { paths.forEach((path) => { this.pathsSet.add(path); }); } collectFiles(files = []) { files.forEach((file) => { const existing = this.filesMap.get(file.filepath) || []; const otherProject = existing.filter((i) => i.projectName !== file.projectName); otherProject.push(file); this.filesMap.set(file.filepath, otherProject); this.updateId(file); }); } // this file is reused by ws-client, and shoult not rely on heavy dependencies like workspace clearFiles(_project, paths = []) { const project = _project; paths.forEach((path) => { const files = this.filesMap.get(path); if (!files) return; const filtered = files.filter((file) => file.projectName !== project.config.name); if (!filtered.length) this.filesMap.delete(path); else this.filesMap.set(path, filtered); }); } updateId(task) { if (this.idMap.get(task.id) === task) return; this.idMap.set(task.id, task); if (task.type === "suite") { task.tasks.forEach((task2) => { this.updateId(task2); }); } } 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 == null ? void 0 : 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) => { var _a; return ((_a = t.result) == null ? void 0 : _a.state) === "fail"; }).length; } cancelFiles(files, root, projectName) { this.collectFiles(files.map((filepath) => ({ filepath, name: relative(root, filepath), id: filepath, mode: "skip", type: "suite", result: { state: "skip" }, meta: {}, // Cancelled files have not yet collected tests tasks: [], projectName }))); } } var _a, _b; const defaultInclude = ["**/*.{test,spec}.?(c|m)[jt]s?(x)"]; const defaultExclude = ["**/node_modules/**", "**/dist/**", "**/cypress/**", "**/.{idea,git,cache,output,temp}/**", "**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*"]; const benchmarkConfigDefaults = { include: ["**/*.{bench,benchmark}.?(c|m)[jt]s?(x)"], exclude: defaultExclude, includeSource: [], reporters: ["default"] }; const defaultCoverageExcludes = [ "coverage/**", "dist/**", "**/[.]**", "packages/*/test?(s)/**", "**/*.d.ts", "**/virtual:*", "**/__x00__*", "**/\0*", "cypress/**", "test?(s)/**", "test?(-*).?(c|m)[jt]s?(x)", "**/*{.,-}{test,spec}?(-d).?(c|m)[jt]s?(x)", "**/__tests__/**", "**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*", "**/vitest.{workspace,projects}.[jt]s?(on)", "**/.{eslint,mocha,prettier}rc.{?(c|m)js,yml}" ]; const coverageConfigDefaults = { provider: "v8", enabled: false, all: true, clean: true, cleanOnRerun: true, reportsDirectory: "./coverage", exclude: defaultCoverageExcludes, reportOnFailure: false, reporter: [["text", {}], ["html", {}], ["clover", {}], ["json", {}]], extension: [".js", ".cjs", ".mjs", ".ts", ".mts", ".cts", ".tsx", ".jsx", ".vue", ".svelte", ".marko"], allowExternal: false, ignoreEmptyLines: false, processingConcurrency: Math.min(20, ((_b = (_a = nodeos__default).availableParallelism) == null ? void 0 : _b.call(_a)) ?? nodeos__default.cpus().length) }; const fakeTimersDefaults = { loopLimit: 1e4, shouldClearNativeTimers: true, toFake: [ "setTimeout", "clearTimeout", "setInterval", "clearInterval", "setImmediate", "clearImmediate", "Date" ] }; const config = { allowOnly: !isCI, isolate: true, watch: !isCI, globals: false, environment: "node", pool: "threads", clearMocks: false, restoreMocks: false, mockReset: false, include: defaultInclude, exclude: defaultExclude, testTimeout: 5e3, hookTimeout: 1e4, teardownTimeout: 1e4, watchExclude: ["**/node_modules/**", "**/dist/**"], forceRerunTriggers: [ "**/package.json/**", "**/{vitest,vite}.config.*/**" ], update: false, reporters: [], silent: false, hideSkippedTests: false, api: false, ui: false, uiBase: "/__vitest__/", open: !isCI, css: { include: [] }, coverage: coverageConfigDefaults, fakeTimers: fakeTimersDefaults, maxConcurrency: 5, dangerouslyIgnoreUnhandledErrors: false, typecheck: { checker: "tsc", include: ["**/*.{test,spec}-d.?(c|m)[jt]s?(x)"], exclude: defaultExclude }, slowTestThreshold: 300, disableConsoleIntercept: false }; const configDefaults = Object.freeze(config); class FilesStatsCache { cache = /* @__PURE__ */ new Map(); getStats(key) { return this.cache.get(key); } async populateStats(root, specs) { const promises = specs.map((spec) => { const key = `${spec[0].getName()}:${relative(root, spec[1])}`; return this.updateStats(spec[1], key); }); await Promise.all(promises); } async updateStats(fsPath, key) { if (!fs$8.existsSync(fsPath)) return; const stats = await fs$8.promises.stat(fsPath); this.cache.set(key, { size: stats.size }); } removeStats(fsPath) { this.cache.forEach((_, key) => { if (key.endsWith(fsPath)) this.cache.delete(key); }); } } class ResultsCache { cache = /* @__PURE__ */ new Map(); workspacesKeyMap = /* @__PURE__ */ new Map(); cachePath = null; version = version; root = "/"; getCachePath() { return this.cachePath; } setConfig(root, config) { this.root = root; if (config) this.cachePath = resolve(config.dir, "results.json"); } getResults(key) { return this.cache.get(key); } async readFromCache() { if (!this.cachePath) return; if (!fs$8.existsSync(this.cachePath)) return; const resultsCache = await fs$8.promises.readFile(this.cachePath, "utf8"); const { results, version: version2 } = JSON.parse(resultsCache || "[]"); if (Number(version2.split(".")[1]) >= 30) { this.cache = new Map(results); this.version = version2; results.forEach(([spec]) => { const [projectName, relativePath] = spec.split(":"); const keyMap = this.workspacesKeyMap.get(relativePath) || []; keyMap.push(projectName); this.workspacesKeyMap.set(relativePath, keyMap); }); } } updateResults(files) { files.forEach((file) => { const result = file.result; if (!result) return; const duration = result.duration || 0; const relativePath = relative(this.root, file.filepath); this.cache.set(`${file.projectName || ""}:${relativePath}`, { duration: duration >= 0 ? duration : 0, failed: result.state === "fail" }); }); } removeFromCache(filepath) { this.cache.forEach((_, key) => { if (key.endsWith(filepath)) this.cache.delete(key); }); } async writeToCache() { if (!this.cachePath) return; const results = Array.from(this.cache.entries()); const cacheDirname = dirname(this.cachePath); if (!fs$8.existsSync(cacheDirname)) await fs$8.promises.mkdir(cacheDirname, { recursive: true }); const cache = JSON.stringify({ version: this.version, results }); await fs$8.promises.writeFile(this.cachePath, cache); } } class VitestCache { results = new ResultsCache(); stats = new FilesStatsCache(); getFileTestResults(key) { return this.results.getResults(key); } getFileStats(key) { return this.stats.getStats(key); } static resolveCacheDir(root, dir, projectName) { const baseDir = slash$1(dir || "node_modules/.vite/vitest"); return projectName ? resolve(root, baseDir, crypto.createHash("md5").update(projectName, "utf-8").digest("hex")) : resolve(root, baseDir); } } function resolvePath(path, root) { return normalize( resolveModule(path, { paths: [root] }) ?? resolve(root, path) ); } function parseInspector(inspect) { if (typeof inspect === "boolean" || inspect === void 0) return {}; if (typeof inspect === "number") return { port: inspect }; if (inspect.match(/https?:\//)) throw new Error(`Inspector host cannot be a URL. Use "host:port" instead of "${inspect}"`); const [host, port] = inspect.split(":"); if (!port) return { host }; return { host, port: Number(port) || defaultInspectPort }; } function resolveApiServerConfig(options) { let api; if (options.ui && !options.api) api = { port: defaultPort }; else if (options.api === true) api = { port: defaultPort }; else if (typeof options.api === "number") api = { port: options.api }; if (typeof options.api === "object") { if (api) { if (options.api.port) api.port = options.api.port; if (options.api.strictPort) api.strictPort = options.api.strictPort; if (options.api.host) api.host = options.api.host; } else { api = { ...options.api }; } } if (api) { if (!api.port && !api.middlewareMode) api.port = defaultPort; } else { api = { middlewareMode: true }; } return api; } function resolveConfig(mode, options, viteConfig, logger) { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M; if (options.dom) { if (((_a = viteConfig.test) == null ? void 0 : _a.environment) != null && viteConfig.test.environment !== "happy-dom") { logger.console.warn( c.yellow( `${c.inverse(c.yellow(" Vitest "))} Your config.test.environment ("${viteConfig.test.environment}") conflicts with --dom flag ("happy-dom"), ignoring "${viteConfig.test.environment}"` ) ); } options.environment = "happy-dom"; } const resolved = { ...configDefaults, ...options, root: viteConfig.root, mode }; const inspector = resolved.inspect || resolved.inspectBrk; resolved.inspector = { ...resolved.inspector, ...parseInspector(inspector), enabled: !!inspector, waitForDebugger: ((_b = options.inspector) == null ? void 0 : _b.waitForDebugger) ?? !!resolved.inspectBrk }; if (viteConfig.base !== "/") resolved.base = viteConfig.base; resolved.clearScreen = resolved.clearScreen ?? viteConfig.clearScreen ?? true; if (options.shard) { if (resolved.watch) throw new Error("You cannot use --shard option with enabled watch"); const [indexString, countString] = options.shard.split("/"); const index = Math.abs(Number.parseInt(indexString, 10)); const count = Math.abs(Number.parseInt(countString, 10)); if (Number.isNaN(count) || count <= 0) throw new Error("--shard must be a positive number"); if (Number.isNaN(index) || index <= 0 || index > count) throw new Error("--shard must be a positive number less then "); resolved.shard = { index, count }; } if (resolved.standalone && !resolved.watch) throw new Error(`Vitest standalone mode requires --watch`); if (resolved.maxWorkers) resolved.maxWorkers = Number(resolved.maxWorkers); if (resolved.minWorkers) resolved.minWorkers = Number(resolved.minWorkers); resolved.browser ?? (resolved.browser = {}); (_c = resolved.browser).fileParallelism ?? (_c.fileParallelism = resolved.fileParallelism ?? false); resolved.fileParallelism ?? (resolved.fileParallelism = mode !== "benchmark"); if (!resolved.fileParallelism) { resolved.maxWorkers = 1; resolved.minWorkers = 1; } if (resolved.inspect || resolved.inspectBrk) { const isSingleThread = resolved.pool === "threads" && ((_e = (_d = resolved.poolOptions) == null ? void 0 : _d.threads) == null ? void 0 : _e.singleThread); const isSingleFork = resolved.pool === "forks" && ((_g = (_f = resolved.poolOptions) == null ? void 0 : _f.forks) == null ? void 0 : _g.singleFork); if (resolved.fileParallelism && !isSingleThread && !isSingleFork) { const inspectOption = `--inspect${resolved.inspectBrk ? "-brk" : ""}`; throw new Error(`You cannot use ${inspectOption} without "--no-file-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"`); } } if (resolved.coverage.provider === "c8") throw new Error('"coverage.provider: c8" is not supported anymore. Use "coverage.provider: v8" instead'); if (resolved.coverage.provider === "v8" && resolved.coverage.enabled && isBrowserEnabled(resolved)) throw new Error("@vitest/coverage-v8 does not work with --browser. Use @vitest/coverage-istanbul instead"); if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) { const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory); if (reportsDirectory === resolved.root || reportsDirectory === process.cwd()) throw new Error(`You cannot set "coverage.reportsDirectory" as ${reportsDirectory}. Vitest needs to be able to remove this directory before test run`); } resolved.deps ?? (resolved.deps = {}); (_h = resolved.deps).moduleDirectories ?? (_h.moduleDirectories = []); resolved.deps.moduleDirectories = resolved.deps.moduleDirectories.map((dir) => { if (!dir.startsWith("/")) dir = `/${dir}`; if (!dir.endsWith("/")) dir += "/"; return normalize(dir); }); if (!resolved.deps.moduleDirectories.includes("/node_modules/")) resolved.deps.moduleDirectories.push("/node_modules/"); (_i = resolved.deps).optimizer ?? (_i.optimizer = {}); (_j = resolved.deps.optimizer).ssr ?? (_j.ssr = {}); (_k = resolved.deps.optimizer.ssr).enabled ?? (_k.enabled = true); (_l = resolved.deps.optimizer).web ?? (_l.web = {}); (_m = resolved.deps.optimizer.web).enabled ?? (_m.enabled = true); (_n = resolved.deps).web ?? (_n.web = {}); (_o = resolved.deps.web).transformAssets ?? (_o.transformAssets = true); (_p = resolved.deps.web).transformCss ?? (_p.transformCss = true); (_q = resolved.deps.web).transformGlobPattern ?? (_q.transformGlobPattern = []); resolved.server ?? (resolved.server = {}); (_r = resolved.server).deps ?? (_r.deps = {}); const deprecatedDepsOptions = ["inline", "external", "fallbackCJS"]; deprecatedDepsOptions.forEach((option) => { if (resolved.deps[option] === void 0) return; if (option === "fallbackCJS") { logger.console.warn(c.yellow(`${c.inverse(c.yellow(" Vitest "))} "deps.${option}" is deprecated. Use "server.deps.${option}" instead`)); } else { const transformMode = resolved.environment === "happy-dom" || resolved.environment === "jsdom" ? "web" : "ssr"; logger.console.warn( c.yellow( `${c.inverse(c.yellow(" Vitest "))} "deps.${option}" is deprecated. If you rely on vite-node directly, use "server.deps.${option}" instead. Otherwise, consider using "deps.optimizer.${transformMode}.${option === "external" ? "exclude" : "include"}"` ) ); } if (resolved.server.deps[option] === void 0) resolved.server.deps[option] = resolved.deps[option]; }); if (resolved.cliExclude) resolved.exclude.push(...resolved.cliExclude); if (resolved.server.deps.inline !== true) { const ssrOptions = viteConfig.ssr; if ((ssrOptions == null ? void 0 : ssrOptions.noExternal) === true && resolved.server.deps.inline == null) { resolved.server.deps.inline = true; } else { (_s = resolved.server.deps).inline ?? (_s.inline = []); resolved.server.deps.inline.push(...extraInlineDeps); } } (_t = resolved.server.deps).moduleDirectories ?? (_t.moduleDirectories = []); resolved.server.deps.moduleDirectories.push(...resolved.deps.moduleDirectories); if (resolved.runner) resolved.runner = resolvePath(resolved.runner, resolved.root); if (resolved.snapshotEnvironment) resolved.snapshotEnvironment = resolvePath(resolved.snapshotEnvironment, resolved.root); resolved.testNamePattern = resolved.testNamePattern ? resolved.testNamePattern instanceof RegExp ? resolved.testNamePattern : new RegExp(resolved.testNamePattern) : void 0; if (resolved.snapshotFormat && "plugins" in resolved.snapshotFormat) resolved.snapshotFormat.plugins = []; const UPDATE_SNAPSHOT = resolved.update || process.env.UPDATE_SNAPSHOT; resolved.snapshotOptions = { expand: resolved.expandSnapshotDiff ?? false, snapshotFormat: resolved.snapshotFormat || {}, updateSnapshot: isCI && !UPDATE_SNAPSHOT ? "none" : UPDATE_SNAPSHOT ? "all" : "new", resolveSnapshotPath: options.resolveSnapshotPath, // resolved inside the worker snapshotEnvironment: null }; resolved.snapshotSerializers ?? (resolved.snapshotSerializers = []); resolved.snapshotSerializers = resolved.snapshotSerializers.map( (file) => resolvePath(file, resolved.root) ); resolved.forceRerunTriggers.push(...resolved.snapshotSerializers); if (options.resolveSnapshotPath) delete resolved.resolveSnapshotPath; resolved.pool ?? (resolved.pool = "threads"); if (process.env.VITEST_MAX_THREADS) { resolved.poolOptions = { ...resolved.poolOptions, threads: { ...(_u = resolved.poolOptions) == null ? void 0 : _u.threads, maxThreads: Number.parseInt(process.env.VITEST_MAX_THREADS) }, vmThreads: { ...(_v = resolved.poolOptions) == null ? void 0 : _v.vmThreads, maxThreads: Number.parseInt(process.env.VITEST_MAX_THREADS) } }; } if (process.env.VITEST_MIN_THREADS) { resolved.poolOptions = { ...resolved.poolOptions, threads: { ...(_w = resolved.poolOptions) == null ? void 0 : _w.threads, minThreads: Number.parseInt(process.env.VITEST_MIN_THREADS) }, vmThreads: { ...(_x = resolved.poolOptions) == null ? void 0 : _x.vmThreads, minThreads: Number.parseInt(process.env.VITEST_MIN_THREADS) } }; } if (process.env.VITEST_MAX_FORKS) { resolved.poolOptions = { ...resolved.poolOptions, forks: { ...(_y = resolved.poolOptions) == null ? void 0 : _y.forks, maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS) }, vmForks: { ...(_z = resolved.poolOptions) == null ? void 0 : _z.vmForks, maxForks: Number.parseInt(process.env.VITEST_MAX_FORKS) } }; } if (process.env.VITEST_MIN_FORKS) { resolved.poolOptions = { ...resolved.poolOptions, forks: { ...(_A = resolved.poolOptions) == null ? void 0 : _A.forks, minForks: Number.parseInt(process.env.VITEST_MIN_FORKS) }, vmForks: { ...(_B = resolved.poolOptions) == null ? void 0 : _B.vmForks, minForks: Number.parseInt(process.env.VITEST_MIN_FORKS) } }; } if (resolved.workspace) { resolved.workspace = options.workspace && options.workspace[0] === "." ? resolve(process.cwd(), options.workspace) : resolvePath(resolved.workspace, resolved.root); } if (!builtinPools.includes(resolved.pool)) resolved.pool = resolvePath(resolved.pool, resolved.root); resolved.poolMatchGlobs = (resolved.poolMatchGlobs || []).map(([glob, pool]) => { if (!builtinPools.includes(pool)) pool = resolvePath(pool, resolved.root); return [glob, pool]; }); if (mode === "benchmark") { resolved.benchmark = { ...benchmarkConfigDefaults, ...resolved.benchmark }; resolved.coverage.enabled = false; resolved.include = resolved.benchmark.include; resolved.exclude = resolved.benchmark.exclude; resolved.includeSource = resolved.benchmark.includeSource; const reporters = Array.from(/* @__PURE__ */ new Set([ ...toArray(resolved.benchmark.reporters), // @ts-expect-error reporter is CLI flag ...toArray(options.reporter) ])).filter(Boolean); if (reporters.length) resolved.benchmark.reporters = reporters; else resolved.benchmark.reporters = ["default"]; if (options.outputFile) resolved.benchmark.outputFile = options.outputFile; if (options.compare) resolved.benchmark.compare = options.compare; if (options.outputJson) resolved.benchmark.outputJson = options.outputJson; } resolved.setupFiles = toArray(resolved.setupFiles || []).map( (file) => resolvePath(file, resolved.root) ); resolved.globalSetup = toArray(resolved.globalSetup || []).map( (file) => resolvePath(file, resolved.root) ); resolved.coverage.exclude.push(...resolved.setupFiles.map((file) => `${resolved.coverage.allowExternal ? "**/" : ""}${relative(resolved.root, file)}`)); resolved.forceRerunTriggers = [ ...resolved.forceRerunTriggers, ...resolved.setupFiles ]; if (resolved.diff) { resolved.diff = resolvePath(resolved.diff, resolved.root); resolved.forceRerunTriggers.push(resolved.diff); } const api = resolveApiServerConfig(options); resolved.api = { ...api, token: crypto.randomUUID() }; if (options.related) resolved.related = toArray(options.related).map((file) => resolve(resolved.root, file)); if (options.reporters) { if (!Array.isArray(options.reporters)) { if (typeof options.reporters === "string") resolved.reporters = [[options.reporters, {}]]; else resolved.reporters = [options.reporters]; } else { resolved.reporters = []; for (const reporter of options.reporters) { if (Array.isArray(reporter)) { resolved.reporters.push([reporter[0], reporter[1] || {}]); } else if (typeof reporter === "string") { resolved.reporters.push([reporter, {}]); } else { resolved.reporters.push(reporter); } } } } if (mode !== "benchmark") { const reportersFromCLI = resolved.reporter; const cliReporters = toArray(reportersFromCLI || []).map((reporter) => { if (/^\.\.?\//.test(reporter)) return resolve(process.cwd(), reporter); return reporter; }); if (cliReporters.length) resolved.reporters = Array.from(new Set(toArray(cliReporters))).filter(Boolean).map((reporter) => [reporter, {}]); } if (!resolved.reporters.length) { resolved.reporters.push(["default", {}]); if (process.env.GITHUB_ACTIONS === "true") resolved.reporters.push(["github-actions", {}]); } if (resolved.changed) resolved.passWithNoTests ?? (resolved.passWithNoTests = true); resolved.css ?? (resolved.css = {}); if (typeof resolved.css === "object") { (_C = resolved.css).modules ?? (_C.modules = {}); (_D = resolved.css.modules).classNameStrategy ?? (_D.classNameStrategy = "stable"); } if (resolved.cache !== false) { let cacheDir = VitestCache.resolveCacheDir("", resolve(viteConfig.cacheDir, "vitest"), resolved.name); if (resolved.cache && resolved.cache.dir) { logger.console.warn( c.yellow( `${c.inverse(c.yellow(" Vitest "))} "cache.dir" is deprecated, use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir/vitest"` ) ); cacheDir = VitestCache.resolveCacheDir(resolved.root, resolved.cache.dir, resolved.name); } resolved.cache = { dir: cacheDir }; } resolved.sequence ?? (resolved.sequence = {}); if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === "object") { const { files, tests } = resolved.sequence.shuffle; (_E = resolved.sequence).sequencer ?? (_E.sequencer = files ? RandomSequencer : BaseSequencer); resolved.sequence.shuffle = tests; } if (!((_F = resolved.sequence) == null ? void 0 : _F.sequencer)) { resolved.sequence.sequencer = resolved.sequence.shuffle ? RandomSequencer : BaseSequencer; } (_G = resolved.sequence).hooks ?? (_G.hooks = "parallel"); if (resolved.sequence.sequencer === RandomSequencer) (_H = resolved.sequence).seed ?? (_H.seed = Date.now()); resolved.typecheck = { ...configDefaults.typecheck, ...resolved.typecheck }; resolved.environmentMatchGlobs = (resolved.environmentMatchGlobs || []).map((i) => [resolve(resolved.root, i[0]), i[1]]); resolved.typecheck ?? (resolved.typecheck = {}); (_I = resolved.typecheck).enabled ?? (_I.enabled = false); if (resolved.typecheck.enabled) logger.console.warn(c.yellow("Testing types with tsc and vue-tsc is an experimental feature.\nBreaking changes might not follow SemVer, please pin Vitest's version when using it.")); resolved.browser ?? (resolved.browser = {}); (_J = resolved.browser).enabled ?? (_J.enabled = false); (_K = resolved.browser).headless ?? (_K.headless = isCI); (_L = resolved.browser).slowHijackESM ?? (_L.slowHijackESM = false); (_M = resolved.browser).isolate ?? (_M.isolate = true); if (resolved.browser.enabled && provider$1 === "stackblitz") resolved.browser.provider = "none"; resolved.browser.api = resolveApiServerConfig(resolved.browser) || { port: defaultBrowserPort }; resolved.testTransformMode ?? (resolved.testTransformMode = {}); return resolved; } function isBrowserEnabled(config) { var _a; return Boolean((_a = config.browser) == null ? void 0 : _a.enabled); } function CoverageTransform(ctx) { return { name: "vitest:coverage-transform", transform(srcCode, id) { var _a, _b; return (_b = (_a = ctx.coverageProvider) == null ? void 0 : _a.onFileTransform) == null ? void 0 : _b.call(_a, srcCode, normalizeRequestId(id), this); } }; } const API_NOT_FOUND_ERROR = `There are some problems in resolving the mocks API. You may encounter this issue when importing the mocks API from another module other than 'vitest'. To fix this issue you can either: - import the mocks API directly from 'vitest' - enable the 'globals' options`; const API_NOT_FOUND_CHECK = ` if (typeof globalThis.vi === "undefined" && typeof globalThis.vitest === "undefined") { throw new Error(${JSON.stringify(API_NOT_FOUND_ERROR)}) } `; function isIdentifier(node) { return node.type === "Identifier"; } function transformImportSpecifiers(node) { const dynamicImports = node.specifiers.map((specifier) => { if (specifier.type === "ImportDefaultSpecifier") return `default: ${specifier.local.name}`; if (specifier.type === "ImportSpecifier") { const local = specifier.local.name; const imported = specifier.imported.name; if (local === imported) return local; return `${imported}: ${local}`; } return null; }).filter(Boolean).join(", "); if (!dynamicImports.length) return ""; return `{ ${dynamicImports} }`; } function getBetterEnd(code, node) { let end = node.end; if (code[node.end] === ";") end += 1; if (code[node.end + 1] === "\n") end += 1; return end; } const regexpHoistable = /\b(vi|vitest)\s*\.\s*(mock|unmock|hoisted)\(/; const hashbangRE = /^#!.*\n/; function hoistMocks(code, id, parse, colors) { var _a; const needHoisting = regexpHoistable.test(code); if (!needHoisting) return; const s = new MagicString(code); let ast; try { ast = parse(code); } catch (err) { console.error(`Cannot parse ${id}: ${err.message}`); return; } const hoistIndex = ((_a = code.match(hashbangRE)) == null ? void 0 : _a[0].length) ?? 0; let hoistedVitestImports = ""; let uid = 0; const idToImportMap = /* @__PURE__ */ new Map(); const transformImportDeclaration = (node) => { const source = node.source.value; const importId = `__vi_import_${uid++}__`; const hasSpecifiers = node.specifiers.length > 0; const code2 = hasSpecifiers ? `const ${importId} = await import('${source}') ` : `await import('${source}') `; return { code: code2, id: importId }; }; function defineImport(node) { if (node.source.value === "vitest") { const code2 = `const ${transformImportSpecifiers(node)} = await import('vitest') `; hoistedVitestImports += code2; s.remove(node.start, getBetterEnd(code2, node)); return; } const declaration = transformImportDeclaration(node); if (!declaration) return null; s.appendLeft(hoistIndex, declaration.code); return declaration.id; } for (const node of ast.body) { if (node.type === "ImportDeclaration") { const importId = defineImport(node); if (!importId) continue; s.remove(node.start, getBetterEnd(code, node)); for (const spec of node.specifiers) { if (spec.type === "ImportSpecifier") { idToImportMap.set( spec.local.name, `${importId}.${spec.imported.name}` ); } else if (spec.type === "ImportDefaultSpecifier") { idToImportMap.set(spec.local.name, `${importId}.default`); } else { idToImportMap.set(spec.local.name, importId); } } } } const declaredConst = /* @__PURE__ */ new Set(); const hoistedNodes = []; function createSyntaxError(node, message) { const _error = new SyntaxError(message); Error.captureStackTrace(_error, createSyntaxError); return { name: "SyntaxError", message: _error.message, stack: _error.stack, frame: generateCodeFrame(highlightCode(id, code, colors), 4, node.start + 1) }; } function assertNotDefaultExport(node, error) { var _a2; const defaultExport = (_a2 = findNodeAround(ast, node.start, "ExportDefaultDeclaration")) == null ? void 0 : _a2.node; if ((defaultExport == null ? void 0 : defaultExport.declaration) === node || (defaultExport == null ? void 0 : defaultExport.declaration.type) === "AwaitExpression" && defaultExport.declaration.argument === node) throw createSyntaxError(defaultExport, error); } function assertNotNamedExport(node, error) { var _a2; const nodeExported = (_a2 = findNodeAround(ast, node.start, "ExportNamedDeclaration")) == null ? void 0 : _a2.node; if ((nodeExported == null ? void 0 : nodeExported.declaration) === node) throw createSyntaxError(nodeExported, error); } function getVariableDeclaration(node) { var _a2, _b; const declarationNode = (_a2 = findNodeAround(ast, node.start, "VariableDeclaration")) == null ? void 0 : _a2.node; const init = (_b = declarationNode == null ? void 0 : declarationNode.declarations[0]) == null ? void 0 : _b.init; if (init && (init === node || init.type === "AwaitExpression" && init.argument === node)) return declarationNode; } esmWalker(ast, { onIdentifier(id2, info, parentStack) { const binding = idToImportMap.get(id2.name); if (!binding) return; if (info.hasBindingShortcut) { s.appendLeft(id2.end, `: ${binding}`); } else if (info.classDeclaration) { if (!declaredConst.has(id2.name)) { declaredConst.add(id2.name); const topNode = parentStack[parentStack.length - 2]; s.prependRight(topNode.start, `const ${id2.name} = ${binding}; `); } } else if ( // don't transform class name identifier !info.classExpression ) { s.update(id2.start, id2.end, binding); } }, onCallExpression(node) { var _a2; if (node.callee.type === "MemberExpression" && isIdentifier(node.callee.object) && (node.callee.object.name === "vi" || node.callee.object.name === "vitest") && isIdentifier(node.callee.property)) { const methodName = node.callee.property.name; if (methodName === "mock" || methodName === "unmock") { const method = `${node.callee.object.name}.${methodName}`; assertNotDefaultExport(node, `Cannot export the result of "${method}". Remove export declaration because "${method}" doesn't return anything.`); const declarationNode = getVariableDeclaration(node); if (declarationNode) assertNotNamedExport(declarationNode, `Cannot export the result of "${method}". Remove export declaration because "${method}" doesn't return anything.`); hoistedNodes.push(node); } if (methodName === "hoisted") { assertNotDefaultExport(node, "Cannot export hoisted variable. You can control hoisting behavior by placing the import from this file first."); const declarationNode = getVariableDeclaration(node); if (declarationNode) { assertNotNamedExport(declarationNode, "Cannot export hoisted variable. You can control hoisting behavior by placing the import from this file first."); hoistedNodes.push(declarationNode); } else { const awaitedExpression = (_a2 = findNodeAround(ast, node.start, "AwaitExpression")) == null ? void 0 : _a2.node; hoistedNodes.push((awaitedExpression == null ? void 0 : awaitedExpression.argument) === node ? awaitedExpression : node); } } } } }); function getNodeName(node) { const callee = node.callee || {}; if (callee.type === "MemberExpression" && isIdentifier(callee.property) && isIdentifier(callee.object)) return `${callee.object.name}.${callee.property.name}()`; return '"hoisted method"'; } function getNodeCall(node) { if (node.type === "CallExpression") return node; if (node.type === "VariableDeclaration") { const { declarations } = node; const init = declarations[0].init; if (init) return getNodeCall(init); } if (node.type === "AwaitExpression") { const { argument } = node; if (argument.type === "CallExpression") return getNodeCall(argument); } return node; } function createError(outsideNode, insideNode) { const outsideCall = getNodeCall(outsideNode); const insideCall = getNodeCall(insideNode); throw createSyntaxError( insideCall, `Cannot call ${getNodeName(insideCall)} inside ${getNodeName(outsideCall)}: both methods are hoisted to the top of the file and not actually called inside each other.` ); } for (let i = 0; i < hoistedNodes.length; i++) { const node = hoistedNodes[i]; for (let j = i + 1; j < hoistedNodes.length; j++) { const otherNode = hoistedNodes[j]; if (node.start >= otherNode.start && node.end <= otherNode.end) throw createError(otherNode, node); if (otherNode.start >= node.start && otherNode.end <= node.end) throw createError(node, otherNode); } } const hoistedCode = hoistedNodes.map((node) => { const end = getBetterEnd(code, node); const nodeCode = s.slice(node.start, end); s.remove(node.start, end); return `${nodeCode}${nodeCode.endsWith("\n") ? "" : "\n"}`; }).join(""); if (hoistedCode || hoistedVitestImports) { s.prepend( hoistedVitestImports + (!hoistedVitestImports && hoistedCode ? API_NOT_FOUND_CHECK : "") + hoistedCode ); } return { ast, code: s.toString(), map: s.generateMap({ hires: "boundary", source: id }) }; } function MocksPlugin() { return { name: "vitest:mocks", enforce: "post", transform(code, id) { return hoistMocks(code, id, this.parse); } }; } function resolveOptimizerConfig(_testOptions, viteOptions, testConfig) { var _a; const testOptions = _testOptions || {}; const newConfig = {}; const [major, minor, fix] = version$1.split(".").map(Number); const allowed = major >= 5 || major === 4 && minor >= 4 || major === 4 && minor === 3 && fix >= 2; if (!allowed && (testOptions == null ? void 0 : testOptions.enabled) === true) console.warn(`Vitest: "deps.optimizer" is only available in Vite >= 4.3.2, current Vite version: ${version$1}`); else testOptions.enabled ?? (testOptions.enabled = false); if (!allowed || (testOptions == null ? void 0 : 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 ? (_a = testConfig.cache) == null ? void 0 : _a.dir : void 0; const currentInclude = testOptions.include || (viteOptions == null ? void 0 : 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 == null ? void 0 : viteOptions.exclude) || [] ]; const runtime = currentInclude.filter((n) => n.endsWith("jsx-dev-runtime") || n.endsWith("jsx-runtime")); exclude.push(...runtime); const include = (testOptions.include || (viteOptions == null ? void 0 : 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) { 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]; } async function createBrowserServer(project, configFile) { var _a; const root = project.config.root; await project.ctx.packageInstaller.ensureInstalled("@vitest/browser", root); const configPath = typeof configFile === "string" ? configFile : false; const server = await createServer({ ...project.options, // spread project config inlined in root workspace config logLevel: "error", mode: project.config.mode, configFile: configPath, // watch is handled by Vitest server: { hmr: false, watch: { ignored: ["**/**"] } }, plugins: [ ...((_a = project.options) == null ? void 0 : _a.plugins) || [], (await import('@vitest/browser')).default(project, "/"), CoverageTransform(project.ctx), { enforce: "post", name: "vitest:browser:config", async config(config) { var _a2, _b, _c; const server2 = resolveApiServerConfig(((_a2 = config.test) == null ? void 0 : _a2.browser) || {}) || { port: defaultBrowserPort }; server2.middlewareMode = false; config.server = { ...config.server, ...server2 }; (_b = config.server).fs ?? (_b.fs = {}); config.server.fs.allow = config.server.fs.allow || []; config.server.fs.allow.push( ...resolveFsAllow( project.ctx.config.root, project.ctx.server.config.configFile ) ); return { resolve: { alias: (_c = config.test) == null ? void 0 : _c.alias }, server: { watch: null } }; } }, MocksPlugin() ] }); await server.listen(); (await Promise.resolve().then(function () { return setup$1; })).setup(project, server); return server; } const builtinProviders = ["webdriverio", "playwright", "none"]; async function getBrowserProvider(options, project) { if (options.provider == null || builtinProviders.includes(options.provider)) { await project.ctx.packageInstaller.ensureInstalled("@vitest/browser", project.config.root); const providers = await project.runner.executeId("@vitest/browser/providers"); const provider = options.provider || "webdriverio"; return providers[provider]; } let customProviderModule; try { customProviderModule = await project.runner.executeId(options.provider); } catch (error) { throw new Error(`Failed to load custom BrowserProvider from ${options.provider}`, { cause: error }); } if (customProviderModule.default == null) throw new Error(`Custom BrowserProvider loaded from ${options.provider} was not the default export`); return customProviderModule.default; } function generateCssFilenameHash(filepath) { return createHash$2("md5").update(filepath).digest("hex").slice(0, 6); } function generateScopedClassName(strategy, name, filename) { if (strategy === "scoped") return null; if (strategy === "non-scoped") return name; const hash = generateCssFilenameHash(filename); return `_${name}_${hash}`; } 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) { var _a; if (!isCSS(id) || shouldProcessCSS(id)) return; if (isCSSModule(id) && !isInline(id)) { const scopeStrategy = typeof ctx.config.css !== "boolean" && ((_a = ctx.config.css.modules) == null ? void 0 : _a.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 ""' }; } } ]; } 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 || (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 VitestResolver(ctx) { return { name: "vitest:resolve-root", enforce: "pre", async resolveId(id) { if (id === "vitest" || id.startsWith("@vitest/")) { return this.resolve( id, join(ctx.config.root, "index.html"), { skipSelf: true } ); } } }; } function VitestOptimizer() { return { name: "vitest:normalize-optimizer", config: { order: "post", handler(viteConfig) { var _a, _b, _c, _d, _e; const testConfig = viteConfig.test || {}; const webOptimizer = resolveOptimizerConfig((_b = (_a = testConfig.deps) == null ? void 0 : _a.optimizer) == null ? void 0 : _b.web, viteConfig.optimizeDeps, testConfig); const ssrOptimizer = resolveOptimizerConfig((_d = (_c = testConfig.deps) == null ? void 0 : _c.optimizer) == null ? void 0 : _d.ssr, (_e = viteConfig.ssr) == null ? void 0 : _e.optimizeDeps, testConfig); viteConfig.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || viteConfig.cacheDir; viteConfig.optimizeDeps = webOptimizer.optimizeDeps; viteConfig.ssr ?? (viteConfig.ssr = {}); viteConfig.ssr.optimizeDeps = ssrOptimizer.optimizeDeps; } } }; } 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 == null ? void 0 : 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 WorkspaceVitestPlugin(project, options) { return [ { name: "vitest:project", enforce: "pre", options() { this.meta.watchMode = false; }, config(viteConfig) { var _a, _b, _c; 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: { 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, preTransformRequests: false, middlewareMode: true, fs: { allow: resolveFsAllow( project.ctx.config.root, project.ctx.server.config.configFile ) } }, test: { name } }; config.test.defines = defines; const classNameStrategy = typeof testConfig.css !== "boolean" && ((_b = (_a = testConfig.css) == null ? void 0 : _a.modules) == null ? void 0 : _b.classNameStrategy) || "stable"; if (classNameStrategy !== "scoped") { config.css ?? (config.css = {}); (_c = config.css).modules ?? (_c.modules = {}); if (config.css.modules) { config.css.modules.generateScopedName = (name2, filename) => { const root2 = project.config.root; return generateScopedClassName(classNameStrategy, name2, relative(root2, filename)); }; } } return config; }, configResolved(viteConfig) { hijackVitePluginInject(viteConfig); }, async configureServer(server) { try { const options2 = deepMerge( {}, configDefaults, server.config.test || {} ); await project.setServer(options2, server); } catch (err) { await project.ctx.logger.printError(err, { fullStack: true }); process.exit(1); } await server.watcher.close(); } }, SsrReplacerPlugin(), ...CSSEnablerPlugin(project), CoverageTransform(project.ctx), MocksPlugin(), VitestResolver(project.ctx), VitestOptimizer(), NormalizeURLPlugin() ]; } 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({ logLevel: "error", ...inlineConfig }); console.error = error; return server; } async function loadGlobalSetupFiles(runner, globalSetup) { const globalSetupFiles = toArray$1(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`); } } async function initializeProject(workspacePath, ctx, options) { var _a; const project = new WorkspaceProject(workspacePath, ctx, options); const configFile = options.extends ? resolve(dirname(options.workspaceConfigPath), options.extends) : typeof workspacePath === "number" || workspacePath.endsWith("/") ? false : workspacePath; const root = options.root || (typeof workspacePath === "number" ? void 0 : workspacePath.endsWith("/") ? workspacePath : dirname(workspacePath)); const config = { ...options, root, logLevel: "error", configFile, // this will make "mode": "test" | "benchmark" inside defineConfig mode: ((_a = options.test) == null ? void 0 : _a.mode) || options.mode || ctx.config.mode, plugins: [ ...options.plugins || [], WorkspaceVitestPlugin(project, { ...options, root, workspacePath }) ] }; await createViteServer(config); return project; } class WorkspaceProject { constructor(path, ctx, options) { this.path = path; this.ctx = ctx; this.options = options; } configOverride; config; server; vitenode; runner; browser; typechecker; closingPromise; browserProvider; browserState; testFilesList = null; 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 }; } async initializeGlobalSetup() { var _a; if (this._globalSetups) return; this._globalSetups = await loadGlobalSetupFiles(this.runner, this.config.globalSetup); try { for (const globalSetupFile of this._globalSetups) { const teardown = await ((_a = globalSetupFile.setup) == null ? void 0 : _a.call(globalSetupFile, { provide: this.provide, config: this.config })); if (teardown == null || !!globalSetupFile.teardown) continue; if (typeof teardown !== "function") throw new Error(`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`); globalSetupFile.teardown = teardown; } } catch (e) { this.logger.error(` ${c.red(divider(c.bold(c.inverse(" Error during global setup "))))}`); await this.logger.printError(e); process.exit(1); } } async teardownGlobalSetup() { var _a; if (!this._globalSetups) return; for (const globalSetupFile of [...this._globalSetups].reverse()) { try { await ((_a = globalSetupFile.teardown) == null ? void 0 : _a.call(globalSetupFile)); } catch (error) { this.logger.error(`error during global teardown of ${globalSetupFile.file}`, error); await this.logger.printError(error); process.exitCode = 1; } } } get logger() { return this.ctx.logger; } // it's possible that file path was imported with different queries (?raw, ?url, etc) getModulesByFilepath(file) { var _a; const set = this.server.moduleGraph.getModulesByFile(file) || ((_a = this.browser) == null ? void 0 : _a.moduleGraph.getModulesByFile(file)); return set || /* @__PURE__ */ new Set(); } getModuleById(id) { var _a; return this.server.moduleGraph.getModuleById(id) || ((_a = this.browser) == null ? void 0 : _a.moduleGraph.getModuleById(id)); } getSourceMapModuleById(id) { var _a, _b; const mod = this.server.moduleGraph.getModuleById(id); return ((_a = mod == null ? void 0 : mod.ssrTransformResult) == null ? void 0 : _a.map) || ((_b = mod == null ? void 0 : mod.transformResult) == null ? void 0 : _b.map); } getBrowserSourceMapModuleById(id) { var _a, _b, _c; return (_c = (_b = (_a = this.browser) == null ? void 0 : _a.moduleGraph.getModuleById(id)) == null ? void 0 : _b.transformResult) == null ? void 0 : _c.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.globFiles(typecheck.include, typecheck.exclude, dir) : [] ]); return this.filterFiles([...testFiles, ...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 == null ? void 0 : includeSource.length) { const files = await this.globFiles(includeSource, exclude, cwd); await Promise.all(files.map(async (file) => { try { const code = await promises$1.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); } async globFiles(include, exclude, cwd) { const globOptions = { dot: true, cwd, ignore: exclude }; const files = await fg(include, globOptions); return files.map((file) => resolve(cwd, file)); } async isTargetFile(id, source) { var _a; 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 (((_a = this.config.includeSource) == null ? void 0 : _a.length) && mm.isMatch(relativeId, this.config.includeSource)) { source = source || await promises$1.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) => toNamespacedPath(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(configFile) { var _a; if (!this.isBrowserEnabled()) return; await ((_a = this.browser) == null ? void 0 : _a.close()); this.browser = await createBrowserServer(this, configFile); } 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; return project; } static async createCoreProject(ctx) { const project = WorkspaceProject.createBasicProject(ctx); await project.initBrowserServer(ctx.server.config.configFile); return project; } async setServer(options, server) { this.config = resolveConfig( this.ctx.mode, { ...options, coverage: this.ctx.config.coverage }, server.config, this.ctx.logger ); 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); } }); await this.initBrowserServer(this.server.config.configFile); } isBrowserEnabled() { return isBrowserEnabled(this.config); } getSerializableConfig() { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v; const optimizer = (_a = this.config.deps) == null ? void 0 : _a.optimizer; const poolOptions = this.config.poolOptions; const isolate = (_d = (_c = (_b = this.server) == null ? void 0 : _b.config) == null ? void 0 : _c.test) == null ? void 0 : _d.isolate; return deepMerge({ ...this.config, poolOptions: { forks: { singleFork: ((_e = poolOptions == null ? void 0 : poolOptions.forks) == null ? void 0 : _e.singleFork) ?? ((_g = (_f = this.ctx.config.poolOptions) == null ? void 0 : _f.forks) == null ? void 0 : _g.singleFork) ?? false, isolate: ((_h = poolOptions == null ? void 0 : poolOptions.forks) == null ? void 0 : _h.isolate) ?? isolate ?? ((_j = (_i = this.ctx.config.poolOptions) == null ? void 0 : _i.forks) == null ? void 0 : _j.isolate) ?? true }, threads: { singleThread: ((_k = poolOptions == null ? void 0 : poolOptions.threads) == null ? void 0 : _k.singleThread) ?? ((_m = (_l = this.ctx.config.poolOptions) == null ? void 0 : _l.threads) == null ? void 0 : _m.singleThread) ?? false, isolate: ((_n = poolOptions == null ? void 0 : poolOptions.threads) == null ? void 0 : _n.isolate) ?? isolate ?? ((_p = (_o = this.ctx.config.poolOptions) == null ? void 0 : _o.threads) == null ? void 0 : _p.isolate) ?? true }, vmThreads: { singleThread: ((_q = poolOptions == null ? void 0 : poolOptions.vmThreads) == null ? void 0 : _q.singleThread) ?? ((_s = (_r = this.ctx.config.poolOptions) == null ? void 0 : _r.vmThreads) == null ? void 0 : _s.singleThread) ?? false } }, reporters: [], deps: { ...this.config.deps, optimizer: { web: { enabled: ((_t = optimizer == null ? void 0 : optimizer.web) == null ? void 0 : _t.enabled) ?? true }, ssr: { enabled: ((_u = optimizer == null ? void 0 : optimizer.ssr) == null ? void 0 : _u.enabled) ?? true } } }, snapshotOptions: { ...this.ctx.config.snapshotOptions, expand: this.config.snapshotOptions.expand ?? this.ctx.config.snapshotOptions.expand, resolveSnapshotPath: void 0 }, onConsoleLog: void 0, onStackTrace: void 0, sequence: { ...this.ctx.config.sequence, sequencer: void 0 }, benchmark: { ...this.config.benchmark, reporters: [] }, inspect: this.ctx.config.inspect, inspectBrk: this.ctx.config.inspectBrk, inspector: this.ctx.config.inspector, alias: [], includeTaskLocation: this.config.includeTaskLocation ?? this.ctx.config.includeTaskLocation, env: { ...(_v = this.server) == null ? void 0 : _v.config.env, ...this.config.env } }, this.ctx.configOverride || {}); } close() { var _a, _b; if (!this.closingPromise) { this.closingPromise = Promise.all([ this.server.close(), (_a = this.typechecker) == null ? void 0 : _a.stop(), (_b = this.browser) == null ? void 0 : _b.close(), this.clearTmpDir() ].filter(Boolean)).then(() => this._provided = {}); } return this.closingPromise; } async clearTmpDir() { try { await rm(this.tmpDir, { force: true, recursive: true }); } catch { } } async initBrowserProvider() { if (!this.isBrowserEnabled()) return; if (this.browserProvider) return; const Provider = await getBrowserProvider(this.config.browser, this); this.browserProvider = new Provider(); const browser = this.config.browser.name; const supportedBrowsers = this.browserProvider.getSupportedBrowsers(); if (!browser) throw new Error(`[${this.getName()}] Browser name is required. Please, set \`test.browser.name\` option manually.`); if (supportedBrowsers.length && !supportedBrowsers.includes(browser)) throw new Error(`[${this.getName()}] Browser "${browser}" is not supported by the browser provider "${this.browserProvider.name}". Supported browsers: ${supportedBrowsers.join(", ")}.`); const providerOptions = this.config.browser.providerOptions; await this.browserProvider.initialize(this, { browser, options: providerOptions }); } } const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); class VitestPackageInstaller { async ensureInstalled(dependency, root) { 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 (error) { } } if (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 Promise.resolve().then(function () { return index; }); const { install } = await prompts.prompt({ type: "confirm", name: "install", message: c.reset(`Do you want to install ${c.green(dependency)}?`) }); if (install) { await (await import('../chunks/install-pkg.LE8oaA1t.js')).installPackage(dependency, { dev: true }); process.stderr.write(c.yellow(` Package ${dependency} installed, re-run the command to start. `)); process.exit(EXIT_CODE_RESTART); return true; } return false; } } 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(); } 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; resolvedProjects = []; projects = []; projectsTestFiles = /* @__PURE__ */ new Map(); distPath; _onRestartListeners = []; _onClose = []; _onSetServer = []; _onCancelListeners = []; async setServer(options, server, cliOptions) { var _a, _b, _c, _d; (_a = this.unregisterWatcher) == null ? void 0 : _a.call(this); clearTimeout(this._rerunTimer); this.restartsCount += 1; (_c = (_b = this.pool) == null ? void 0 : _b.close) == null ? void 0 : _c.call(_b); this.pool = void 0; this.coverageProvider = void 0; this.runningPromise = void 0; this.distPath = void 0; this.projectsTestFiles.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.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())); await serverRestart(...args); this.unregisterWatcher(); this.registerWatcher(); }; server.watcher.on("change", async (file) => { file = normalize(file); const isConfig = file === server.config.configFile; if (isConfig) { await Promise.all(this._onRestartListeners.map((fn) => fn("config"))); await serverRestart(); this.unregisterWatcher(); this.registerWatcher(); } }); } this.reporters = resolved.mode === "benchmark" ? await createBenchmarkReporters(toArray((_d = resolved.benchmark) == null ? void 0 : _d.reporters), this.runner) : await createReporters(resolved.reporters, this); this.cache.results.setConfig(resolved.root, resolved.cache); try { await this.cache.results.readFromCache(); } catch { } await Promise.all(this._onSetServer.map((fn) => fn())); 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; } async createCoreProject() { this.coreWorkspaceProject = await WorkspaceProject.createCoreProject(this); return this.coreWorkspaceProject; } getCoreWorkspaceProject() { return this.coreWorkspaceProject; } getProjectByTaskId(taskId) { var _a; const task = this.state.idMap.get(taskId); const projectName = task.projectName || ((_a = task == null ? void 0 : task.file) == null ? void 0 : _a.projectName); return this.projects.find((p) => p.getName() === projectName) || 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$1.readdir(configDir); const workspaceConfigName = workspacesFiles.find((configFile) => { return rootFiles.includes(configFile); }); if (!workspaceConfigName) return null; return join(configDir, workspaceConfigName); } async resolveWorkspace(cliOptions) { const workspaceConfigPath = await this.getWorkspaceConfigPath(); if (!workspaceConfigPath) return [await this.createCoreProject()]; const workspaceModule = await this.runner.executeFile(workspaceConfigPath); if (!workspaceModule.default || !Array.isArray(workspaceModule.default)) throw new Error(`Workspace config file ${workspaceConfigPath} must export a default array of project paths.`); const workspaceGlobMatches = []; const projectsOptions = []; for (const project of workspaceModule.default) { if (typeof project === "string") { workspaceGlobMatches.push(project.replace("", this.config.root)); } else if (typeof project === "function") { projectsOptions.push(await project({ command: this.server.config.command, mode: this.server.config.mode, isPreview: false, isSsrBuild: false })); } else { projectsOptions.push(await project); } } const globOptions = { absolute: true, dot: true, onlyFiles: false, markDirectories: true, cwd: this.config.root, ignore: ["**/node_modules/**", "**/*.timestamp-*"] }; const workspacesFs = await fg(workspaceGlobMatches, globOptions); const resolvedWorkspacesPaths = await Promise.all(workspacesFs.filter((file) => { if (file.endsWith("/")) { const hasWorkspaceWithConfig = workspacesFs.some((file2) => { return file2 !== file && `${dirname(file2)}/` === file; }); return !hasWorkspaceWithConfig; } const filename = basename(file); return CONFIG_NAMES.some((configName) => filename.startsWith(configName)); }).map(async (filepath) => { if (filepath.endsWith("/")) { const filesInside = await promises$1.readdir(filepath); const configFile = configFiles.find((config) => filesInside.includes(config)); return configFile ? join(filepath, configFile) : filepath; } return filepath; })); const workspacesByFolder = resolvedWorkspacesPaths.reduce((configByFolder, filepath) => { const dir = filepath.endsWith("/") ? filepath.slice(0, -1) : dirname(filepath); configByFolder[dir] ?? (configByFolder[dir] = []); configByFolder[dir].push(filepath); return configByFolder; }, {}); const filteredWorkspaces = Object.values(workspacesByFolder).map((configFiles2) => { if (configFiles2.length === 1) return configFiles2[0]; const vitestConfig = configFiles2.find((configFile) => basename(configFile).startsWith("vitest.config")); return vitestConfig || configFiles2[0]; }); const overridesOptions = [ "logHeapUsage", "allowOnly", "sequence", "testTimeout", "pool", "update", "globals", "expandSnapshotDiff", "disableConsoleIntercept", "retry", "testNamePattern", "passWithNoTests", "bail", "isolate" ]; const cliOverrides = overridesOptions.reduce((acc, name) => { if (name in cliOptions) acc[name] = cliOptions[name]; return acc; }, {}); const cwd = process.cwd(); const projects = []; try { for (const filepath of filteredWorkspaces) { if (this.server.config.configFile === filepath) { const project = await this.createCoreProject(); projects.push(project); continue; } const dir = filepath.endsWith("/") ? filepath.slice(0, -1) : dirname(filepath); if (isMainThread) process.chdir(dir); projects.push( await initializeProject(filepath, this, { workspaceConfigPath, test: cliOverrides }) ); } } finally { if (isMainThread) process.chdir(cwd); } const projectPromises = []; projectsOptions.forEach((options, index) => { projectPromises.push(initializeProject(index, this, mergeConfig(options, { workspaceConfigPath, test: cliOverrides }))); }); if (!projects.length && !projectPromises.length) return [await this.createCoreProject()]; const resolvedProjects = await Promise.all([ ...projects, ...await Promise.all(projectPromises) ]); const names = /* @__PURE__ */ new Set(); for (const project of resolvedProjects) { const name = project.getName(); if (names.has(name)) throw new Error(`Project name "${name}" is not unique. All projects in a workspace should have unique names.`); names.add(name); } return resolvedProjects; } 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 initBrowserProviders() { return Promise.all(this.projects.map((w) => w.initBrowserProvider())); } async start(filters) { var _a, _b; this._onClose = []; try { await this.initCoverageProvider(); await ((_a = this.coverageProvider) == null ? void 0 : _a.clean(this.config.coverage.clean)); await this.initBrowserProviders(); } finally { await this.report("onInit", this); } const files = await this.filterTestsBySource( await this.globTestFiles(filters) ); if (!files.length) { await this.reportCoverage(true); this.logger.printNoTestFound(filters); if (!this.config.watch || !(this.config.changed || ((_b = this.config.related) == null ? void 0 : _b.length))) { const exitCode = this.config.passWithNoTests ? 0 : 1; process.exit(exitCode); } } 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() { var _a; this._onClose = []; try { await this.initCoverageProvider(); await ((_a = this.coverageProvider) == null ? void 0 : _a.clean(this.config.coverage.clean)); await this.initBrowserProviders(); } finally { await this.report("onInit", this); } await this.globTestFiles(); if (this.config.watch) await this.report("onWatcherStart"); } async getTestDependencies(filepath, deps = /* @__PURE__ */ new Set()) { const addImports = async ([project, filepath2]) => { if (deps.has(filepath2)) return; deps.add(filepath2); const mod = project.server.moduleGraph.getModuleById(filepath2); const transformed = (mod == null ? void 0 : mod.ssrTransformResult) || await project.vitenode.transformRequest(filepath2); if (!transformed) return; const dependencies = [...transformed.deps || [], ...transformed.dynamicDeps || []]; await Promise.all(dependencies.map(async (dep) => { const path = await project.server.pluginContainer.resolveId(dep, filepath2, { 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(filepath); deps.delete(filepath[1]); return deps; } async filterTestsBySource(specs) { if (this.config.changed && !this.config.related) { const { VitestGit } = await import('../chunks/node-git.Hw101KjS.js'); const vitestGit = new VitestGit(this.config.root); const related2 = await vitestGit.findChangedFiles({ changedSince: this.config.changed }); if (!related2) { this.logger.error(c.red("Could not find Git root. Have you initialized git with `git init`?\n")); process.exit(1); } 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; } getProjectsByTestFile(file) { const projects = this.projectsTestFiles.get(file); if (!projects) return []; return Array.from(projects).map((project) => [project, file]); } async initializeGlobalSetup(paths) { const projects = new Set(paths.map(([project]) => project)); const coreProject = this.getCoreWorkspaceProject(); if (!projects.has(coreProject)) projects.add(coreProject); for await (const project of projects) await project.initializeGlobalSetup(); } async initializeDistPath() { if (this.distPath) return; const projectVitestPath = await this.vitenode.resolveId("vitest"); const vitestDir = projectVitestPath ? resolve(projectVitestPath.id, "../..") : rootDir; this.distPath = join(vitestDir, "dist"); } async runFiles(paths, allTestsRun) { await this.initializeDistPath(); const filepaths = paths.map(([, file]) => file); this.state.collectPaths(filepaths); await this.report("onPathsCollected", filepaths); await this.runningPromise; this._onCancelListeners = []; this.isCancelling = false; this.runningPromise = (async () => { var _a; 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 ((_a = this.coverageProvider) == null ? void 0 : _a.clean()); await this.initializeGlobalSetup(paths); try { await this.pool.runTests(paths, 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 specs = Array.from(new Set(paths.map(([, p]) => p))); await this.report("onFinished", this.state.getFiles(specs), this.state.getUnhandledErrors()); await this.reportCoverage(allTestsRun); this.runningPromise = void 0; this.isFirstRun = false; 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 rerunFiles(files = this.state.getFilepaths(), trigger) { 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)), !trigger); 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.globTestFiles()).map(([, file]) => file); await this.rerunFiles(files, "change project filter"); } 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); } 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); } async rerunFailed() { await this.rerunFiles(this.state.getFailedFilepaths(), "rerun failed"); } 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"); } 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$1(test)) ); } unregisterWatcher = noop$2; registerWatcher() { const updateLastChanged = (filepath) => { const projects = this.getModuleProjects(filepath); projects.forEach(({ server, browser }) => { const serverMods = server.moduleGraph.getModulesByFile(filepath); serverMods == null ? void 0 : serverMods.forEach((mod) => server.moduleGraph.invalidateModule(mod)); if (browser) { const browserMods = browser.moduleGraph.getModulesByFile(filepath); browserMods == null ? void 0 : browserMods.forEach((mod) => browser.moduleGraph.invalidateModule(mod)); } }); }; const onChange = (id) => { id = slash$1(id); this.logger.clearHighlightCache(id); updateLastChanged(id); const needsRerun = this.handleFileChanged(id); if (needsRerun.length) this.scheduleRerun(needsRerun); }; const onUnlink = (id) => { id = slash$1(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); } }; const onAdd = async (id) => { id = slash$1(id); updateLastChanged(id); const matchingProjects = []; await Promise.all(this.projects.map(async (project) => { var _a; if (await project.isTargetFile(id)) { matchingProjects.push(project); (_a = project.testFilesList) == null ? void 0 : _a.push(id); } })); if (matchingProjects.length > 0) { this.projectsTestFiles.set(id, new Set(matchingProjects)); this.changedTests.add(id); this.scheduleRerun([id]); } else { const needsRerun = this.handleFileChanged(id); if (needsRerun.length) this.scheduleRerun(needsRerun); } }; const watcher = this.server.watcher; if (this.config.forceRerunTriggers.length) watcher.add(this.config.forceRerunTriggers); watcher.unwatch(this.config.watchExclude); watcher.on("change", onChange); watcher.on("unlink", onUnlink); watcher.on("add", onAdd); this.unregisterWatcher = () => { watcher.off("change", onChange); watcher.off("unlink", onUnlink); watcher.off("add", onAdd); this.unregisterWatcher = noop$2; }; } /** * @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(allTestsRun) { if (!this.config.coverage.reportOnFailure && this.state.getCountOfFailedTests() > 0) return; if (this.coverageProvider) { await this.coverageProvider.reportCoverage({ 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 () => { var _a, _b; await ((_b = (_a = this.pool) == null ? void 0 : _a.close) == null ? void 0 : _b.call(_a)); this.pool = void 0; })()); } closePromises.push(...this._onClose.map((fn) => fn())); return Promise.allSettled(closePromises).then((results) => { results.filter((r) => r.status === "rejected").forEach((err) => { this.logger.error("error during close", err.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) => { var _a; return (_a = r[name]) == null ? void 0 : _a.call( r, ...args ); })); } async getTestFilepaths() { return this.globTestFiles().then((files) => files.map(([, file]) => file)); } async globTestFiles(filters = []) { const files = []; await Promise.all(this.projects.map(async (project) => { const specs = await project.globTestFiles(filters); specs.forEach((file) => { files.push([project, file]); const projects = this.projectsTestFiles.get(file) || /* @__PURE__ */ new Set(); projects.add(project); this.projectsTestFiles.set(file, projects); }); })); return files; } // The server needs to be running for communication shouldKeepServer() { var _a; return !!((_a = this.config) == null ? void 0 : _a.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 = () => { var _a; return ((_a = ctx.config) == null ? void 0 : _a.root) || options.root || process.cwd(); }; async function UIPlugin() { await ctx.packageInstaller.ensureInstalled("@vitest/ui", getRoot()); return (await import('@vitest/ui')).default(ctx); } return [ { name: "vitest", enforce: "pre", options() { this.meta.watchMode = false; }, async config(viteConfig) { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r; if (options.watch) { options = deepMerge({}, userConfig); } const testConfig = deepMerge( {}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options ); testConfig.api = resolveApiServerConfig(testConfig); const defines = deleteDefineConfig(viteConfig); options.defines = defines; let open = false; if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/"; const config = { root: ((_a = viteConfig.test) == null ? void 0 : _a.root) || options.root, esbuild: viteConfig.esbuild === false ? false : { 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, watch: { ignored: testConfig.watchExclude }, open, hmr: false, 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 }, test: { poolOptions: { threads: { isolate: ((_c = (_b = options.poolOptions) == null ? void 0 : _b.threads) == null ? void 0 : _c.isolate) ?? options.isolate ?? ((_e = (_d = testConfig.poolOptions) == null ? void 0 : _d.threads) == null ? void 0 : _e.isolate) ?? ((_f = viteConfig.test) == null ? void 0 : _f.isolate) }, forks: { isolate: ((_h = (_g = options.poolOptions) == null ? void 0 : _g.threads) == null ? void 0 : _h.isolate) ?? options.isolate ?? ((_j = (_i = testConfig.poolOptions) == null ? void 0 : _i.threads) == null ? void 0 : _j.isolate) ?? ((_k = viteConfig.test) == null ? void 0 : _k.isolate) } } } }; if (((_l = viteConfig.ssr) == null ? void 0 : _l.noExternal) !== true) { const inline = (_n = (_m = testConfig.server) == null ? void 0 : _m.deps) == null ? void 0 : _n.inline; if (inline === true) { config.ssr = { noExternal: true }; } else { const noExternal = (_o = viteConfig.ssr) == null ? void 0 : _o.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) { config.server.watch.useFsEvents = false; config.server.watch.usePolling = false; } const classNameStrategy = typeof testConfig.css !== "boolean" && ((_q = (_p = testConfig.css) == null ? void 0 : _p.modules) == null ? void 0 : _q.classNameStrategy) || "stable"; if (classNameStrategy !== "scoped") { config.css ?? (config.css = {}); (_r = config.css).modules ?? (_r.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) { var _a, _b, _c; 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); const { PROD, DEV, ...envs } = viteConfig.env; (_a = process.env).PROD ?? (_a.PROD = PROD ? "1" : ""); (_b = process.env).DEV ?? (_b.DEV = DEV ? "1" : ""); for (const name in envs) (_c = process.env)[name] ?? (_c[name] = envs[name]); if (!options.watch) viteConfig.server.watch = null; hijackVitePluginInject(viteConfig); }, async configureServer(server) { if (options.watch && process.env.VITE_TEST_WATCHER_DEBUG) { server.watcher.on("ready", () => { console.log("[debug] watcher is ready"); }); } try { await ctx.setServer(options, server, userConfig); if (options.api && options.watch) (await Promise.resolve().then(function () { return setup$1; })).setup(ctx); } catch (err) { await ctx.logger.printError(err, { fullStack: true }); process.exit(1); } if (!options.watch) await server.watcher.close(); } }, SsrReplacerPlugin(), ...CSSEnablerPlugin(ctx), CoverageTransform(ctx), options.ui ? await UIPlugin() : null, MocksPlugin(), VitestResolver(ctx), VitestOptimizer(), NormalizeURLPlugin() ].filter(notNullish); } async function createVitest(mode, options, viteOverrides = {}, vitestOptions = {}) { var _a; const ctx = new Vitest(mode, vitestOptions); const root = resolve(options.root || process.cwd()); const configPath = options.config === false ? false : options.config ? resolve(root, options.config) : await findUp(configFiles, { cwd: root }); options.config = configPath; const config = { logLevel: "error", 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 ((_a = ctx.config.api) == null ? void 0 : _a.port) await server.listen(); return ctx; } var prompts$2 = {}; var kleur; var hasRequiredKleur; function requireKleur () { if (hasRequiredKleur) return kleur; hasRequiredKleur = 1; const { FORCE_COLOR, NODE_DISABLE_COLORS, TERM } = process.env; const $ = { enabled: !NODE_DISABLE_COLORS && TERM !== 'dumb' && FORCE_COLOR !== '0', // modifiers reset: init(0, 0), bold: init(1, 22), dim: init(2, 22), italic: init(3, 23), underline: init(4, 24), inverse: init(7, 27), hidden: init(8, 28), strikethrough: init(9, 29), // colors black: init(30, 39), red: init(31, 39), green: init(32, 39), yellow: init(33, 39), blue: init(34, 39), magenta: init(35, 39), cyan: init(36, 39), white: init(37, 39), gray: init(90, 39), grey: init(90, 39), // background colors bgBlack: init(40, 49), bgRed: init(41, 49), bgGreen: init(42, 49), bgYellow: init(43, 49), bgBlue: init(44, 49), bgMagenta: init(45, 49), bgCyan: init(46, 49), bgWhite: init(47, 49) }; function run(arr, str) { let i=0, tmp, beg='', end=''; for (; i < arr.length; i++) { tmp = arr[i]; beg += tmp.open; end += tmp.close; if (str.includes(tmp.close)) { str = str.replace(tmp.rgx, tmp.close + tmp.open); } } return beg + str + end; } function chain(has, keys) { let ctx = { has, keys }; ctx.reset = $.reset.bind(ctx); ctx.bold = $.bold.bind(ctx); ctx.dim = $.dim.bind(ctx); ctx.italic = $.italic.bind(ctx); ctx.underline = $.underline.bind(ctx); ctx.inverse = $.inverse.bind(ctx); ctx.hidden = $.hidden.bind(ctx); ctx.strikethrough = $.strikethrough.bind(ctx); ctx.black = $.black.bind(ctx); ctx.red = $.red.bind(ctx); ctx.green = $.green.bind(ctx); ctx.yellow = $.yellow.bind(ctx); ctx.blue = $.blue.bind(ctx); ctx.magenta = $.magenta.bind(ctx); ctx.cyan = $.cyan.bind(ctx); ctx.white = $.white.bind(ctx); ctx.gray = $.gray.bind(ctx); ctx.grey = $.grey.bind(ctx); ctx.bgBlack = $.bgBlack.bind(ctx); ctx.bgRed = $.bgRed.bind(ctx); ctx.bgGreen = $.bgGreen.bind(ctx); ctx.bgYellow = $.bgYellow.bind(ctx); ctx.bgBlue = $.bgBlue.bind(ctx); ctx.bgMagenta = $.bgMagenta.bind(ctx); ctx.bgCyan = $.bgCyan.bind(ctx); ctx.bgWhite = $.bgWhite.bind(ctx); return ctx; } function init(open, close) { let blk = { open: `\x1b[${open}m`, close: `\x1b[${close}m`, rgx: new RegExp(`\\x1b\\[${close}m`, 'g') }; return function (txt) { if (this !== void 0 && this.has !== void 0) { this.has.includes(open) || (this.has.push(open),this.keys.push(blk)); return txt === void 0 ? this : $.enabled ? run(this.keys, txt+'') : txt+''; } return txt === void 0 ? chain([open], [blk]) : $.enabled ? run([blk], txt+'') : txt+''; }; } kleur = $; return kleur; } var action$1; var hasRequiredAction$1; function requireAction$1 () { if (hasRequiredAction$1) return action$1; hasRequiredAction$1 = 1; action$1 = (key, isSelect) => { if (key.meta && key.name !== 'escape') return; if (key.ctrl) { if (key.name === 'a') return 'first'; if (key.name === 'c') return 'abort'; if (key.name === 'd') return 'abort'; if (key.name === 'e') return 'last'; if (key.name === 'g') return 'reset'; } if (isSelect) { if (key.name === 'j') return 'down'; if (key.name === 'k') return 'up'; } if (key.name === 'return') return 'submit'; if (key.name === 'enter') return 'submit'; // ctrl + J if (key.name === 'backspace') return 'delete'; if (key.name === 'delete') return 'deleteForward'; if (key.name === 'abort') return 'abort'; if (key.name === 'escape') return 'exit'; if (key.name === 'tab') return 'next'; if (key.name === 'pagedown') return 'nextPage'; if (key.name === 'pageup') return 'prevPage'; // TODO create home() in prompt types (e.g. TextPrompt) if (key.name === 'home') return 'home'; // TODO create end() in prompt types (e.g. TextPrompt) if (key.name === 'end') return 'end'; if (key.name === 'up') return 'up'; if (key.name === 'down') return 'down'; if (key.name === 'right') return 'right'; if (key.name === 'left') return 'left'; return false; }; return action$1; } var strip$1; var hasRequiredStrip$1; function requireStrip$1 () { if (hasRequiredStrip$1) return strip$1; hasRequiredStrip$1 = 1; strip$1 = str => { const pattern = ['[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))'].join('|'); const RGX = new RegExp(pattern, 'g'); return typeof str === 'string' ? str.replace(RGX, '') : str; }; return strip$1; } var src; var hasRequiredSrc; function requireSrc () { if (hasRequiredSrc) return src; hasRequiredSrc = 1; const ESC = '\x1B'; const CSI = `${ESC}[`; const beep = '\u0007'; const cursor = { to(x, y) { if (!y) return `${CSI}${x + 1}G`; return `${CSI}${y + 1};${x + 1}H`; }, move(x, y) { let ret = ''; if (x < 0) ret += `${CSI}${-x}D`; else if (x > 0) ret += `${CSI}${x}C`; if (y < 0) ret += `${CSI}${-y}A`; else if (y > 0) ret += `${CSI}${y}B`; return ret; }, up: (count = 1) => `${CSI}${count}A`, down: (count = 1) => `${CSI}${count}B`, forward: (count = 1) => `${CSI}${count}C`, backward: (count = 1) => `${CSI}${count}D`, nextLine: (count = 1) => `${CSI}E`.repeat(count), prevLine: (count = 1) => `${CSI}F`.repeat(count), left: `${CSI}G`, hide: `${CSI}?25l`, show: `${CSI}?25h`, save: `${ESC}7`, restore: `${ESC}8` }; const scroll = { up: (count = 1) => `${CSI}S`.repeat(count), down: (count = 1) => `${CSI}T`.repeat(count) }; const erase = { screen: `${CSI}2J`, up: (count = 1) => `${CSI}1J`.repeat(count), down: (count = 1) => `${CSI}J`.repeat(count), line: `${CSI}2K`, lineEnd: `${CSI}K`, lineStart: `${CSI}1K`, lines(count) { let clear = ''; for (let i = 0; i < count; i++) clear += this.line + (i < count - 1 ? cursor.up() : ''); if (count) clear += cursor.left; return clear; } }; src = { cursor, scroll, erase, beep }; return src; } var clear$1; var hasRequiredClear$1; function requireClear$1 () { if (hasRequiredClear$1) return clear$1; hasRequiredClear$1 = 1; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } const strip = requireStrip$1(); const _require = requireSrc(), erase = _require.erase, cursor = _require.cursor; const width = str => [...strip(str)].length; /** * @param {string} prompt * @param {number} perLine */ clear$1 = function (prompt, perLine) { if (!perLine) return erase.line + cursor.to(0); let rows = 0; const lines = prompt.split(/\r?\n/); var _iterator = _createForOfIteratorHelper(lines), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { let line = _step.value; rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return erase.lines(rows); }; return clear$1; } var figures_1$1; var hasRequiredFigures$1; function requireFigures$1 () { if (hasRequiredFigures$1) return figures_1$1; hasRequiredFigures$1 = 1; const main = { arrowUp: '↑', arrowDown: '↓', arrowLeft: '←', arrowRight: '→', radioOn: '◉', radioOff: '◯', tick: '✔', cross: '✖', ellipsis: '…', pointerSmall: '›', line: '─', pointer: '❯' }; const win = { arrowUp: main.arrowUp, arrowDown: main.arrowDown, arrowLeft: main.arrowLeft, arrowRight: main.arrowRight, radioOn: '(*)', radioOff: '( )', tick: '√', cross: '×', ellipsis: '...', pointerSmall: '»', line: '─', pointer: '>' }; const figures = process.platform === 'win32' ? win : main; figures_1$1 = figures; return figures_1$1; } var style$1; var hasRequiredStyle$1; function requireStyle$1 () { if (hasRequiredStyle$1) return style$1; hasRequiredStyle$1 = 1; const c = requireKleur(); const figures = requireFigures$1(); // rendering user input. const styles = Object.freeze({ password: { scale: 1, render: input => '*'.repeat(input.length) }, emoji: { scale: 2, render: input => '😃'.repeat(input.length) }, invisible: { scale: 0, render: input => '' }, default: { scale: 1, render: input => `${input}` } }); const render = type => styles[type] || styles.default; // icon to signalize a prompt. const symbols = Object.freeze({ aborted: c.red(figures.cross), done: c.green(figures.tick), exited: c.yellow(figures.cross), default: c.cyan('?') }); const symbol = (done, aborted, exited) => aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default; // between the question and the user's input. const delimiter = completing => c.gray(completing ? figures.ellipsis : figures.pointerSmall); const item = (expandable, expanded) => c.gray(expandable ? expanded ? figures.pointerSmall : '+' : figures.line); style$1 = { styles, render, symbols, symbol, delimiter, item }; return style$1; } var lines$1; var hasRequiredLines$1; function requireLines$1 () { if (hasRequiredLines$1) return lines$1; hasRequiredLines$1 = 1; const strip = requireStrip$1(); /** * @param {string} msg * @param {number} perLine */ lines$1 = function (msg, perLine) { let lines = String(strip(msg) || '').split(/\r?\n/); if (!perLine) return lines.length; return lines.map(l => Math.ceil(l.length / perLine)).reduce((a, b) => a + b); }; return lines$1; } var wrap$1; var hasRequiredWrap$1; function requireWrap$1 () { if (hasRequiredWrap$1) return wrap$1; hasRequiredWrap$1 = 1; /** * @param {string} msg The message to wrap * @param {object} opts * @param {number|string} [opts.margin] Left margin * @param {number} opts.width Maximum characters per line including the margin */ wrap$1 = (msg, opts = {}) => { const tab = Number.isSafeInteger(parseInt(opts.margin)) ? new Array(parseInt(opts.margin)).fill(' ').join('') : opts.margin || ''; const width = opts.width; return (msg || '').split(/\r?\n/g).map(line => line.split(/\s+/g).reduce((arr, w) => { if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width) arr[arr.length - 1] += ` ${w}`;else arr.push(`${tab}${w}`); return arr; }, [tab]).join('\n')).join('\n'); }; return wrap$1; } var entriesToDisplay$1; var hasRequiredEntriesToDisplay$1; function requireEntriesToDisplay$1 () { if (hasRequiredEntriesToDisplay$1) return entriesToDisplay$1; hasRequiredEntriesToDisplay$1 = 1; /** * Determine what entries should be displayed on the screen, based on the * currently selected index and the maximum visible. Used in list-based * prompts like `select` and `multiselect`. * * @param {number} cursor the currently selected entry * @param {number} total the total entries available to display * @param {number} [maxVisible] the number of entries that can be displayed */ entriesToDisplay$1 = (cursor, total, maxVisible) => { maxVisible = maxVisible || total; let startIndex = Math.min(total - maxVisible, cursor - Math.floor(maxVisible / 2)); if (startIndex < 0) startIndex = 0; let endIndex = Math.min(startIndex + maxVisible, total); return { startIndex, endIndex }; }; return entriesToDisplay$1; } var util$1; var hasRequiredUtil$1; function requireUtil$1 () { if (hasRequiredUtil$1) return util$1; hasRequiredUtil$1 = 1; util$1 = { action: requireAction$1(), clear: requireClear$1(), style: requireStyle$1(), strip: requireStrip$1(), figures: requireFigures$1(), lines: requireLines$1(), wrap: requireWrap$1(), entriesToDisplay: requireEntriesToDisplay$1() }; return util$1; } var prompt$2; var hasRequiredPrompt$1; function requirePrompt$1 () { if (hasRequiredPrompt$1) return prompt$2; hasRequiredPrompt$1 = 1; const readline = require$$0$6; const _require = requireUtil$1(), action = _require.action; const EventEmitter = require$$0$3; const _require2 = requireSrc(), beep = _require2.beep, cursor = _require2.cursor; const color = requireKleur(); /** * Base prompt skeleton * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class Prompt extends EventEmitter { constructor(opts = {}) { super(); this.firstRender = true; this.in = opts.stdin || process.stdin; this.out = opts.stdout || process.stdout; this.onRender = (opts.onRender || (() => void 0)).bind(this); const rl = readline.createInterface({ input: this.in, escapeCodeTimeout: 50 }); readline.emitKeypressEvents(this.in, rl); if (this.in.isTTY) this.in.setRawMode(true); const isSelect = ['SelectPrompt', 'MultiselectPrompt'].indexOf(this.constructor.name) > -1; const keypress = (str, key) => { let a = action(key, isSelect); if (a === false) { this._ && this._(str, key); } else if (typeof this[a] === 'function') { this[a](key); } else { this.bell(); } }; this.close = () => { this.out.write(cursor.show); this.in.removeListener('keypress', keypress); if (this.in.isTTY) this.in.setRawMode(false); rl.close(); this.emit(this.aborted ? 'abort' : this.exited ? 'exit' : 'submit', this.value); this.closed = true; }; this.in.on('keypress', keypress); } fire() { this.emit('state', { value: this.value, aborted: !!this.aborted, exited: !!this.exited }); } bell() { this.out.write(beep); } render() { this.onRender(color); if (this.firstRender) this.firstRender = false; } } prompt$2 = Prompt; return prompt$2; } var text$1; var hasRequiredText$1; function requireText$1 () { if (hasRequiredText$1) return text$1; hasRequiredText$1 = 1; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireSrc(), erase = _require.erase, cursor = _require.cursor; const _require2 = requireUtil$1(), style = _require2.style, clear = _require2.clear, lines = _require2.lines, figures = _require2.figures; /** * TextPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {String} [opts.style='default'] Render style * @param {String} [opts.initial] Default value * @param {Function} [opts.validate] Validate function * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.error] The invalid error label */ class TextPrompt extends Prompt { constructor(opts = {}) { super(opts); this.transform = style.render(opts.style); this.scale = this.transform.scale; this.msg = opts.message; this.initial = opts.initial || ``; this.validator = opts.validate || (() => true); this.value = ``; this.errorMsg = opts.error || `Please Enter A Valid Value`; this.cursor = Number(!!this.initial); this.cursorOffset = 0; this.clear = clear(``, this.out.columns); this.render(); } set value(v) { if (!v && this.initial) { this.placeholder = true; this.rendered = color.gray(this.transform.render(this.initial)); } else { this.placeholder = false; this.rendered = this.transform.render(v); } this._value = v; this.fire(); } get value() { return this._value; } reset() { this.value = ``; this.cursor = Number(!!this.initial); this.cursorOffset = 0; this.fire(); this.render(); } exit() { this.abort(); } abort() { this.value = this.value || this.initial; this.done = this.aborted = true; this.error = false; this.red = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } validate() { var _this = this; return _asyncToGenerator(function* () { let valid = yield _this.validator(_this.value); if (typeof valid === `string`) { _this.errorMsg = valid; valid = false; } _this.error = !valid; })(); } submit() { var _this2 = this; return _asyncToGenerator(function* () { _this2.value = _this2.value || _this2.initial; _this2.cursorOffset = 0; _this2.cursor = _this2.rendered.length; yield _this2.validate(); if (_this2.error) { _this2.red = true; _this2.fire(); _this2.render(); return; } _this2.done = true; _this2.aborted = false; _this2.fire(); _this2.render(); _this2.out.write('\n'); _this2.close(); })(); } next() { if (!this.placeholder) return this.bell(); this.value = this.initial; this.cursor = this.rendered.length; this.fire(); this.render(); } moveCursor(n) { if (this.placeholder) return; this.cursor = this.cursor + n; this.cursorOffset += n; } _(c, key) { let s1 = this.value.slice(0, this.cursor); let s2 = this.value.slice(this.cursor); this.value = `${s1}${c}${s2}`; this.red = false; this.cursor = this.placeholder ? 0 : s1.length + 1; this.render(); } delete() { if (this.isCursorAtStart()) return this.bell(); let s1 = this.value.slice(0, this.cursor - 1); let s2 = this.value.slice(this.cursor); this.value = `${s1}${s2}`; this.red = false; if (this.isCursorAtStart()) { this.cursorOffset = 0; } else { this.cursorOffset++; this.moveCursor(-1); } this.render(); } deleteForward() { if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell(); let s1 = this.value.slice(0, this.cursor); let s2 = this.value.slice(this.cursor + 1); this.value = `${s1}${s2}`; this.red = false; if (this.isCursorAtEnd()) { this.cursorOffset = 0; } else { this.cursorOffset++; } this.render(); } first() { this.cursor = 0; this.render(); } last() { this.cursor = this.value.length; this.render(); } left() { if (this.cursor <= 0 || this.placeholder) return this.bell(); this.moveCursor(-1); this.render(); } right() { if (this.cursor * this.scale >= this.rendered.length || this.placeholder) return this.bell(); this.moveCursor(1); this.render(); } isCursorAtStart() { return this.cursor === 0 || this.placeholder && this.cursor === 1; } isCursorAtEnd() { return this.cursor === this.rendered.length || this.placeholder && this.cursor === this.rendered.length + 1; } render() { if (this.closed) return; if (!this.firstRender) { if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns)); this.out.write(clear(this.outputText, this.out.columns)); } super.render(); this.outputError = ''; this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.red ? color.red(this.rendered) : this.rendered].join(` `); if (this.error) { this.outputError += this.errorMsg.split(`\n`).reduce((a, l, i) => a + `\n${i ? ' ' : figures.pointerSmall} ${color.red().italic(l)}`, ``); } this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0)); } } text$1 = TextPrompt; return text$1; } var select$1; var hasRequiredSelect$1; function requireSelect$1 () { if (hasRequiredSelect$1) return select$1; hasRequiredSelect$1 = 1; const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireUtil$1(), style = _require.style, clear = _require.clear, figures = _require.figures, wrap = _require.wrap, entriesToDisplay = _require.entriesToDisplay; const _require2 = requireSrc(), cursor = _require2.cursor; /** * SelectPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of choice objects * @param {String} [opts.hint] Hint to display * @param {Number} [opts.initial] Index of default value * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {Number} [opts.optionsPerPage=10] Max options to display at once */ class SelectPrompt extends Prompt { constructor(opts = {}) { super(opts); this.msg = opts.message; this.hint = opts.hint || '- Use arrow-keys. Return to submit.'; this.warn = opts.warn || '- This option is disabled'; this.cursor = opts.initial || 0; this.choices = opts.choices.map((ch, idx) => { if (typeof ch === 'string') ch = { title: ch, value: idx }; return { title: ch && (ch.title || ch.value || ch), value: ch && (ch.value === undefined ? idx : ch.value), description: ch && ch.description, selected: ch && ch.selected, disabled: ch && ch.disabled }; }); this.optionsPerPage = opts.optionsPerPage || 10; this.value = (this.choices[this.cursor] || {}).value; this.clear = clear('', this.out.columns); this.render(); } moveCursor(n) { this.cursor = n; this.value = this.choices[n].value; this.fire(); } reset() { this.moveCursor(0); this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { if (!this.selection.disabled) { this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } else this.bell(); } first() { this.moveCursor(0); this.render(); } last() { this.moveCursor(this.choices.length - 1); this.render(); } up() { if (this.cursor === 0) { this.moveCursor(this.choices.length - 1); } else { this.moveCursor(this.cursor - 1); } this.render(); } down() { if (this.cursor === this.choices.length - 1) { this.moveCursor(0); } else { this.moveCursor(this.cursor + 1); } this.render(); } next() { this.moveCursor((this.cursor + 1) % this.choices.length); this.render(); } _(c, key) { if (c === ' ') return this.submit(); } get selection() { return this.choices[this.cursor]; } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns)); super.render(); let _entriesToDisplay = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage), startIndex = _entriesToDisplay.startIndex, endIndex = _entriesToDisplay.endIndex; // Print prompt this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.done ? this.selection.title : this.selection.disabled ? color.yellow(this.warn) : color.gray(this.hint)].join(' '); // Print choices if (!this.done) { this.outputText += '\n'; for (let i = startIndex; i < endIndex; i++) { let title, prefix, desc = '', v = this.choices[i]; // Determine whether to display "more choices" indicators if (i === startIndex && startIndex > 0) { prefix = figures.arrowUp; } else if (i === endIndex - 1 && endIndex < this.choices.length) { prefix = figures.arrowDown; } else { prefix = ' '; } if (v.disabled) { title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title); prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + ' ' : ' ') + prefix; } else { title = this.cursor === i ? color.cyan().underline(v.title) : v.title; prefix = (this.cursor === i ? color.cyan(figures.pointer) + ' ' : ' ') + prefix; if (v.description && this.cursor === i) { desc = ` - ${v.description}`; if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns }); } } } this.outputText += `${prefix} ${title}${color.gray(desc)}\n`; } } this.out.write(this.outputText); } } select$1 = SelectPrompt; return select$1; } var toggle$1; var hasRequiredToggle$1; function requireToggle$1 () { if (hasRequiredToggle$1) return toggle$1; hasRequiredToggle$1 = 1; const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireUtil$1(), style = _require.style, clear = _require.clear; const _require2 = requireSrc(), cursor = _require2.cursor, erase = _require2.erase; /** * TogglePrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Boolean} [opts.initial=false] Default value * @param {String} [opts.active='no'] Active label * @param {String} [opts.inactive='off'] Inactive label * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class TogglePrompt extends Prompt { constructor(opts = {}) { super(opts); this.msg = opts.message; this.value = !!opts.initial; this.active = opts.active || 'on'; this.inactive = opts.inactive || 'off'; this.initialValue = this.value; this.render(); } reset() { this.value = this.initialValue; this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } deactivate() { if (this.value === false) return this.bell(); this.value = false; this.render(); } activate() { if (this.value === true) return this.bell(); this.value = true; this.render(); } delete() { this.deactivate(); } left() { this.deactivate(); } right() { this.activate(); } down() { this.deactivate(); } up() { this.activate(); } next() { this.value = !this.value; this.fire(); this.render(); } _(c, key) { if (c === ' ') { this.value = !this.value; } else if (c === '1') { this.value = true; } else if (c === '0') { this.value = false; } else return this.bell(); this.render(); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns)); super.render(); this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.value ? this.inactive : color.cyan().underline(this.inactive), color.gray('/'), this.value ? color.cyan().underline(this.active) : this.active].join(' '); this.out.write(erase.line + cursor.to(0) + this.outputText); } } toggle$1 = TogglePrompt; return toggle$1; } var datepart$1; var hasRequiredDatepart$1; function requireDatepart$1 () { if (hasRequiredDatepart$1) return datepart$1; hasRequiredDatepart$1 = 1; class DatePart { constructor({ token, date, parts, locales }) { this.token = token; this.date = date || new Date(); this.parts = parts || [this]; this.locales = locales || {}; } up() {} down() {} next() { const currentIdx = this.parts.indexOf(this); return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart); } setTo(val) {} prev() { let parts = [].concat(this.parts).reverse(); const currentIdx = parts.indexOf(this); return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart); } toString() { return String(this.date); } } datepart$1 = DatePart; return datepart$1; } var meridiem$1; var hasRequiredMeridiem$1; function requireMeridiem$1 () { if (hasRequiredMeridiem$1) return meridiem$1; hasRequiredMeridiem$1 = 1; const DatePart = requireDatepart$1(); class Meridiem extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setHours((this.date.getHours() + 12) % 24); } down() { this.up(); } toString() { let meridiem = this.date.getHours() > 12 ? 'pm' : 'am'; return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem; } } meridiem$1 = Meridiem; return meridiem$1; } var day$1; var hasRequiredDay$1; function requireDay$1 () { if (hasRequiredDay$1) return day$1; hasRequiredDay$1 = 1; const DatePart = requireDatepart$1(); const pos = n => { n = n % 10; return n === 1 ? 'st' : n === 2 ? 'nd' : n === 3 ? 'rd' : 'th'; }; class Day extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setDate(this.date.getDate() + 1); } down() { this.date.setDate(this.date.getDate() - 1); } setTo(val) { this.date.setDate(parseInt(val.substr(-2))); } toString() { let date = this.date.getDate(); let day = this.date.getDay(); return this.token === 'DD' ? String(date).padStart(2, '0') : this.token === 'Do' ? date + pos(date) : this.token === 'd' ? day + 1 : this.token === 'ddd' ? this.locales.weekdaysShort[day] : this.token === 'dddd' ? this.locales.weekdays[day] : date; } } day$1 = Day; return day$1; } var hours$1; var hasRequiredHours$1; function requireHours$1 () { if (hasRequiredHours$1) return hours$1; hasRequiredHours$1 = 1; const DatePart = requireDatepart$1(); class Hours extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setHours(this.date.getHours() + 1); } down() { this.date.setHours(this.date.getHours() - 1); } setTo(val) { this.date.setHours(parseInt(val.substr(-2))); } toString() { let hours = this.date.getHours(); if (/h/.test(this.token)) hours = hours % 12 || 12; return this.token.length > 1 ? String(hours).padStart(2, '0') : hours; } } hours$1 = Hours; return hours$1; } var milliseconds$1; var hasRequiredMilliseconds$1; function requireMilliseconds$1 () { if (hasRequiredMilliseconds$1) return milliseconds$1; hasRequiredMilliseconds$1 = 1; const DatePart = requireDatepart$1(); class Milliseconds extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setMilliseconds(this.date.getMilliseconds() + 1); } down() { this.date.setMilliseconds(this.date.getMilliseconds() - 1); } setTo(val) { this.date.setMilliseconds(parseInt(val.substr(-this.token.length))); } toString() { return String(this.date.getMilliseconds()).padStart(4, '0').substr(0, this.token.length); } } milliseconds$1 = Milliseconds; return milliseconds$1; } var minutes$1; var hasRequiredMinutes$1; function requireMinutes$1 () { if (hasRequiredMinutes$1) return minutes$1; hasRequiredMinutes$1 = 1; const DatePart = requireDatepart$1(); class Minutes extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setMinutes(this.date.getMinutes() + 1); } down() { this.date.setMinutes(this.date.getMinutes() - 1); } setTo(val) { this.date.setMinutes(parseInt(val.substr(-2))); } toString() { let m = this.date.getMinutes(); return this.token.length > 1 ? String(m).padStart(2, '0') : m; } } minutes$1 = Minutes; return minutes$1; } var month$1; var hasRequiredMonth$1; function requireMonth$1 () { if (hasRequiredMonth$1) return month$1; hasRequiredMonth$1 = 1; const DatePart = requireDatepart$1(); class Month extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setMonth(this.date.getMonth() + 1); } down() { this.date.setMonth(this.date.getMonth() - 1); } setTo(val) { val = parseInt(val.substr(-2)) - 1; this.date.setMonth(val < 0 ? 0 : val); } toString() { let month = this.date.getMonth(); let tl = this.token.length; return tl === 2 ? String(month + 1).padStart(2, '0') : tl === 3 ? this.locales.monthsShort[month] : tl === 4 ? this.locales.months[month] : String(month + 1); } } month$1 = Month; return month$1; } var seconds$1; var hasRequiredSeconds$1; function requireSeconds$1 () { if (hasRequiredSeconds$1) return seconds$1; hasRequiredSeconds$1 = 1; const DatePart = requireDatepart$1(); class Seconds extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setSeconds(this.date.getSeconds() + 1); } down() { this.date.setSeconds(this.date.getSeconds() - 1); } setTo(val) { this.date.setSeconds(parseInt(val.substr(-2))); } toString() { let s = this.date.getSeconds(); return this.token.length > 1 ? String(s).padStart(2, '0') : s; } } seconds$1 = Seconds; return seconds$1; } var year$1; var hasRequiredYear$1; function requireYear$1 () { if (hasRequiredYear$1) return year$1; hasRequiredYear$1 = 1; const DatePart = requireDatepart$1(); class Year extends DatePart { constructor(opts = {}) { super(opts); } up() { this.date.setFullYear(this.date.getFullYear() + 1); } down() { this.date.setFullYear(this.date.getFullYear() - 1); } setTo(val) { this.date.setFullYear(val.substr(-4)); } toString() { let year = String(this.date.getFullYear()).padStart(4, '0'); return this.token.length === 2 ? year.substr(-2) : year; } } year$1 = Year; return year$1; } var dateparts$1; var hasRequiredDateparts$1; function requireDateparts$1 () { if (hasRequiredDateparts$1) return dateparts$1; hasRequiredDateparts$1 = 1; dateparts$1 = { DatePart: requireDatepart$1(), Meridiem: requireMeridiem$1(), Day: requireDay$1(), Hours: requireHours$1(), Milliseconds: requireMilliseconds$1(), Minutes: requireMinutes$1(), Month: requireMonth$1(), Seconds: requireSeconds$1(), Year: requireYear$1() }; return dateparts$1; } var date$1; var hasRequiredDate$1; function requireDate$1 () { if (hasRequiredDate$1) return date$1; hasRequiredDate$1 = 1; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireUtil$1(), style = _require.style, clear = _require.clear, figures = _require.figures; const _require2 = requireSrc(), erase = _require2.erase, cursor = _require2.cursor; const _require3 = requireDateparts$1(), DatePart = _require3.DatePart, Meridiem = _require3.Meridiem, Day = _require3.Day, Hours = _require3.Hours, Milliseconds = _require3.Milliseconds, Minutes = _require3.Minutes, Month = _require3.Month, Seconds = _require3.Seconds, Year = _require3.Year; const regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g; const regexGroups = { 1: ({ token }) => token.replace(/\\(.)/g, '$1'), 2: opts => new Day(opts), // Day // TODO 3: opts => new Month(opts), // Month 4: opts => new Year(opts), // Year 5: opts => new Meridiem(opts), // AM/PM // TODO (special) 6: opts => new Hours(opts), // Hours 7: opts => new Minutes(opts), // Minutes 8: opts => new Seconds(opts), // Seconds 9: opts => new Milliseconds(opts) // Fractional seconds }; const dfltLocales = { months: 'January,February,March,April,May,June,July,August,September,October,November,December'.split(','), monthsShort: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','), weekdays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','), weekdaysShort: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(',') }; /** * DatePrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Number} [opts.initial] Index of default value * @param {String} [opts.mask] The format mask * @param {object} [opts.locales] The date locales * @param {String} [opts.error] The error message shown on invalid value * @param {Function} [opts.validate] Function to validate the submitted value * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class DatePrompt extends Prompt { constructor(opts = {}) { super(opts); this.msg = opts.message; this.cursor = 0; this.typed = ''; this.locales = Object.assign(dfltLocales, opts.locales); this._date = opts.initial || new Date(); this.errorMsg = opts.error || 'Please Enter A Valid Value'; this.validator = opts.validate || (() => true); this.mask = opts.mask || 'YYYY-MM-DD HH:mm:ss'; this.clear = clear('', this.out.columns); this.render(); } get value() { return this.date; } get date() { return this._date; } set date(date) { if (date) this._date.setTime(date.getTime()); } set mask(mask) { let result; this.parts = []; while (result = regex.exec(mask)) { let match = result.shift(); let idx = result.findIndex(gr => gr != null); this.parts.push(idx in regexGroups ? regexGroups[idx]({ token: result[idx] || match, date: this.date, parts: this.parts, locales: this.locales }) : result[idx] || match); } let parts = this.parts.reduce((arr, i) => { if (typeof i === 'string' && typeof arr[arr.length - 1] === 'string') arr[arr.length - 1] += i;else arr.push(i); return arr; }, []); this.parts.splice(0); this.parts.push(...parts); this.reset(); } moveCursor(n) { this.typed = ''; this.cursor = n; this.fire(); } reset() { this.moveCursor(this.parts.findIndex(p => p instanceof DatePart)); this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.error = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } validate() { var _this = this; return _asyncToGenerator(function* () { let valid = yield _this.validator(_this.value); if (typeof valid === 'string') { _this.errorMsg = valid; valid = false; } _this.error = !valid; })(); } submit() { var _this2 = this; return _asyncToGenerator(function* () { yield _this2.validate(); if (_this2.error) { _this2.color = 'red'; _this2.fire(); _this2.render(); return; } _this2.done = true; _this2.aborted = false; _this2.fire(); _this2.render(); _this2.out.write('\n'); _this2.close(); })(); } up() { this.typed = ''; this.parts[this.cursor].up(); this.render(); } down() { this.typed = ''; this.parts[this.cursor].down(); this.render(); } left() { let prev = this.parts[this.cursor].prev(); if (prev == null) return this.bell(); this.moveCursor(this.parts.indexOf(prev)); this.render(); } right() { let next = this.parts[this.cursor].next(); if (next == null) return this.bell(); this.moveCursor(this.parts.indexOf(next)); this.render(); } next() { let next = this.parts[this.cursor].next(); this.moveCursor(next ? this.parts.indexOf(next) : this.parts.findIndex(part => part instanceof DatePart)); this.render(); } _(c) { if (/\d/.test(c)) { this.typed += c; this.parts[this.cursor].setTo(this.typed); this.render(); } } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns)); super.render(); // Print prompt this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), []).join('')].join(' '); // Print error if (this.error) { this.outputText += this.errorMsg.split('\n').reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``); } this.out.write(erase.line + cursor.to(0) + this.outputText); } } date$1 = DatePrompt; return date$1; } var number$1; var hasRequiredNumber$1; function requireNumber$1 () { if (hasRequiredNumber$1) return number$1; hasRequiredNumber$1 = 1; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireSrc(), cursor = _require.cursor, erase = _require.erase; const _require2 = requireUtil$1(), style = _require2.style, figures = _require2.figures, clear = _require2.clear, lines = _require2.lines; const isNumber = /[0-9]/; const isDef = any => any !== undefined; const round = (number, precision) => { let factor = Math.pow(10, precision); return Math.round(number * factor) / factor; }; /** * NumberPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {String} [opts.style='default'] Render style * @param {Number} [opts.initial] Default value * @param {Number} [opts.max=+Infinity] Max value * @param {Number} [opts.min=-Infinity] Min value * @param {Boolean} [opts.float=false] Parse input as floats * @param {Number} [opts.round=2] Round floats to x decimals * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys * @param {Function} [opts.validate] Validate function * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.error] The invalid error label */ class NumberPrompt extends Prompt { constructor(opts = {}) { super(opts); this.transform = style.render(opts.style); this.msg = opts.message; this.initial = isDef(opts.initial) ? opts.initial : ''; this.float = !!opts.float; this.round = opts.round || 2; this.inc = opts.increment || 1; this.min = isDef(opts.min) ? opts.min : -Infinity; this.max = isDef(opts.max) ? opts.max : Infinity; this.errorMsg = opts.error || `Please Enter A Valid Value`; this.validator = opts.validate || (() => true); this.color = `cyan`; this.value = ``; this.typed = ``; this.lastHit = 0; this.render(); } set value(v) { if (!v && v !== 0) { this.placeholder = true; this.rendered = color.gray(this.transform.render(`${this.initial}`)); this._value = ``; } else { this.placeholder = false; this.rendered = this.transform.render(`${round(v, this.round)}`); this._value = round(v, this.round); } this.fire(); } get value() { return this._value; } parse(x) { return this.float ? parseFloat(x) : parseInt(x); } valid(c) { return c === `-` || c === `.` && this.float || isNumber.test(c); } reset() { this.typed = ``; this.value = ``; this.fire(); this.render(); } exit() { this.abort(); } abort() { let x = this.value; this.value = x !== `` ? x : this.initial; this.done = this.aborted = true; this.error = false; this.fire(); this.render(); this.out.write(`\n`); this.close(); } validate() { var _this = this; return _asyncToGenerator(function* () { let valid = yield _this.validator(_this.value); if (typeof valid === `string`) { _this.errorMsg = valid; valid = false; } _this.error = !valid; })(); } submit() { var _this2 = this; return _asyncToGenerator(function* () { yield _this2.validate(); if (_this2.error) { _this2.color = `red`; _this2.fire(); _this2.render(); return; } let x = _this2.value; _this2.value = x !== `` ? x : _this2.initial; _this2.done = true; _this2.aborted = false; _this2.error = false; _this2.fire(); _this2.render(); _this2.out.write(`\n`); _this2.close(); })(); } up() { this.typed = ``; if (this.value === '') { this.value = this.min - this.inc; } if (this.value >= this.max) return this.bell(); this.value += this.inc; this.color = `cyan`; this.fire(); this.render(); } down() { this.typed = ``; if (this.value === '') { this.value = this.min + this.inc; } if (this.value <= this.min) return this.bell(); this.value -= this.inc; this.color = `cyan`; this.fire(); this.render(); } delete() { let val = this.value.toString(); if (val.length === 0) return this.bell(); this.value = this.parse(val = val.slice(0, -1)) || ``; if (this.value !== '' && this.value < this.min) { this.value = this.min; } this.color = `cyan`; this.fire(); this.render(); } next() { this.value = this.initial; this.fire(); this.render(); } _(c, key) { if (!this.valid(c)) return this.bell(); const now = Date.now(); if (now - this.lastHit > 1000) this.typed = ``; // 1s elapsed this.typed += c; this.lastHit = now; this.color = `cyan`; if (c === `.`) return this.fire(); this.value = Math.min(this.parse(this.typed), this.max); if (this.value > this.max) this.value = this.max; if (this.value < this.min) this.value = this.min; this.fire(); this.render(); } render() { if (this.closed) return; if (!this.firstRender) { if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns)); this.out.write(clear(this.outputText, this.out.columns)); } super.render(); this.outputError = ''; // Print prompt this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), !this.done || !this.done && !this.placeholder ? color[this.color]().underline(this.rendered) : this.rendered].join(` `); // Print error if (this.error) { this.outputError += this.errorMsg.split(`\n`).reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``); } this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore); } } number$1 = NumberPrompt; return number$1; } var multiselect$1; var hasRequiredMultiselect$1; function requireMultiselect$1 () { if (hasRequiredMultiselect$1) return multiselect$1; hasRequiredMultiselect$1 = 1; const color = requireKleur(); const _require = requireSrc(), cursor = _require.cursor; const Prompt = requirePrompt$1(); const _require2 = requireUtil$1(), clear = _require2.clear, figures = _require2.figures, style = _require2.style, wrap = _require2.wrap, entriesToDisplay = _require2.entriesToDisplay; /** * MultiselectPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of choice objects * @param {String} [opts.hint] Hint to display * @param {String} [opts.warn] Hint shown for disabled choices * @param {Number} [opts.max] Max choices * @param {Number} [opts.cursor=0] Cursor start position * @param {Number} [opts.optionsPerPage=10] Max options to display at once * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class MultiselectPrompt extends Prompt { constructor(opts = {}) { super(opts); this.msg = opts.message; this.cursor = opts.cursor || 0; this.scrollIndex = opts.cursor || 0; this.hint = opts.hint || ''; this.warn = opts.warn || '- This option is disabled -'; this.minSelected = opts.min; this.showMinError = false; this.maxChoices = opts.max; this.instructions = opts.instructions; this.optionsPerPage = opts.optionsPerPage || 10; this.value = opts.choices.map((ch, idx) => { if (typeof ch === 'string') ch = { title: ch, value: idx }; return { title: ch && (ch.title || ch.value || ch), description: ch && ch.description, value: ch && (ch.value === undefined ? idx : ch.value), selected: ch && ch.selected, disabled: ch && ch.disabled }; }); this.clear = clear('', this.out.columns); if (!opts.overrideRender) { this.render(); } } reset() { this.value.map(v => !v.selected); this.cursor = 0; this.fire(); this.render(); } selected() { return this.value.filter(v => v.selected); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { const selected = this.value.filter(e => e.selected); if (this.minSelected && selected.length < this.minSelected) { this.showMinError = true; this.render(); } else { this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } } first() { this.cursor = 0; this.render(); } last() { this.cursor = this.value.length - 1; this.render(); } next() { this.cursor = (this.cursor + 1) % this.value.length; this.render(); } up() { if (this.cursor === 0) { this.cursor = this.value.length - 1; } else { this.cursor--; } this.render(); } down() { if (this.cursor === this.value.length - 1) { this.cursor = 0; } else { this.cursor++; } this.render(); } left() { this.value[this.cursor].selected = false; this.render(); } right() { if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell(); this.value[this.cursor].selected = true; this.render(); } handleSpaceToggle() { const v = this.value[this.cursor]; if (v.selected) { v.selected = false; this.render(); } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) { return this.bell(); } else { v.selected = true; this.render(); } } toggleAll() { if (this.maxChoices !== undefined || this.value[this.cursor].disabled) { return this.bell(); } const newSelected = !this.value[this.cursor].selected; this.value.filter(v => !v.disabled).forEach(v => v.selected = newSelected); this.render(); } _(c, key) { if (c === ' ') { this.handleSpaceToggle(); } else if (c === 'a') { this.toggleAll(); } else { return this.bell(); } } renderInstructions() { if (this.instructions === undefined || this.instructions) { if (typeof this.instructions === 'string') { return this.instructions; } return '\nInstructions:\n' + ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option\n` + ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection\n` + (this.maxChoices === undefined ? ` a: Toggle all\n` : '') + ` enter/return: Complete answer`; } return ''; } renderOption(cursor, v, i, arrowIndicator) { const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + arrowIndicator + ' '; let title, desc; if (v.disabled) { title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title); } else { title = cursor === i ? color.cyan().underline(v.title) : v.title; if (cursor === i && v.description) { desc = ` - ${v.description}`; if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { desc = '\n' + wrap(v.description, { margin: prefix.length, width: this.out.columns }); } } } return prefix + title + color.gray(desc || ''); } // shared with autocompleteMultiselect paginateOptions(options) { if (options.length === 0) { return color.red('No matches for this query.'); } let _entriesToDisplay = entriesToDisplay(this.cursor, options.length, this.optionsPerPage), startIndex = _entriesToDisplay.startIndex, endIndex = _entriesToDisplay.endIndex; let prefix, styledOptions = []; for (let i = startIndex; i < endIndex; i++) { if (i === startIndex && startIndex > 0) { prefix = figures.arrowUp; } else if (i === endIndex - 1 && endIndex < options.length) { prefix = figures.arrowDown; } else { prefix = ' '; } styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix)); } return '\n' + styledOptions.join('\n'); } // shared with autocomleteMultiselect renderOptions(options) { if (!this.done) { return this.paginateOptions(options); } return ''; } renderDoneOrInstructions() { if (this.done) { return this.value.filter(e => e.selected).map(v => v.title).join(', '); } const output = [color.gray(this.hint), this.renderInstructions()]; if (this.value[this.cursor].disabled) { output.push(color.yellow(this.warn)); } return output.join(' '); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); super.render(); // print prompt let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions()].join(' '); if (this.showMinError) { prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`); this.showMinError = false; } prompt += this.renderOptions(this.value); this.out.write(this.clear + prompt); this.clear = clear(prompt, this.out.columns); } } multiselect$1 = MultiselectPrompt; return multiselect$1; } var autocomplete$1; var hasRequiredAutocomplete$1; function requireAutocomplete$1 () { if (hasRequiredAutocomplete$1) return autocomplete$1; hasRequiredAutocomplete$1 = 1; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireSrc(), erase = _require.erase, cursor = _require.cursor; const _require2 = requireUtil$1(), style = _require2.style, clear = _require2.clear, figures = _require2.figures, wrap = _require2.wrap, entriesToDisplay = _require2.entriesToDisplay; const getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]); const getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]); const getIndex = (arr, valOrTitle) => { const index = arr.findIndex(el => el.value === valOrTitle || el.title === valOrTitle); return index > -1 ? index : undefined; }; /** * TextPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of auto-complete choices objects * @param {Function} [opts.suggest] Filter function. Defaults to sort by title * @param {Number} [opts.limit=10] Max number of results to show * @param {Number} [opts.cursor=0] Cursor start position * @param {String} [opts.style='default'] Render style * @param {String} [opts.fallback] Fallback message - initial to default value * @param {String} [opts.initial] Index of the default value * @param {Boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.noMatches] The no matches found label */ class AutocompletePrompt extends Prompt { constructor(opts = {}) { super(opts); this.msg = opts.message; this.suggest = opts.suggest; this.choices = opts.choices; this.initial = typeof opts.initial === 'number' ? opts.initial : getIndex(opts.choices, opts.initial); this.select = this.initial || opts.cursor || 0; this.i18n = { noMatches: opts.noMatches || 'no matches found' }; this.fallback = opts.fallback || this.initial; this.clearFirst = opts.clearFirst || false; this.suggestions = []; this.input = ''; this.limit = opts.limit || 10; this.cursor = 0; this.transform = style.render(opts.style); this.scale = this.transform.scale; this.render = this.render.bind(this); this.complete = this.complete.bind(this); this.clear = clear('', this.out.columns); this.complete(this.render); this.render(); } set fallback(fb) { this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb; } get fallback() { let choice; if (typeof this._fb === 'number') choice = this.choices[this._fb];else if (typeof this._fb === 'string') choice = { title: this._fb }; return choice || this._fb || { title: this.i18n.noMatches }; } moveSelect(i) { this.select = i; if (this.suggestions.length > 0) this.value = getVal(this.suggestions, i);else this.value = this.fallback.value; this.fire(); } complete(cb) { var _this = this; return _asyncToGenerator(function* () { const p = _this.completing = _this.suggest(_this.input, _this.choices); const suggestions = yield p; if (_this.completing !== p) return; _this.suggestions = suggestions.map((s, i, arr) => ({ title: getTitle(arr, i), value: getVal(arr, i), description: s.description })); _this.completing = false; const l = Math.max(suggestions.length - 1, 0); _this.moveSelect(Math.min(l, _this.select)); cb && cb(); })(); } reset() { this.input = ''; this.complete(() => { this.moveSelect(this.initial !== void 0 ? this.initial : 0); this.render(); }); this.render(); } exit() { if (this.clearFirst && this.input.length > 0) { this.reset(); } else { this.done = this.exited = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } } abort() { this.done = this.aborted = true; this.exited = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { this.done = true; this.aborted = this.exited = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } _(c, key) { let s1 = this.input.slice(0, this.cursor); let s2 = this.input.slice(this.cursor); this.input = `${s1}${c}${s2}`; this.cursor = s1.length + 1; this.complete(this.render); this.render(); } delete() { if (this.cursor === 0) return this.bell(); let s1 = this.input.slice(0, this.cursor - 1); let s2 = this.input.slice(this.cursor); this.input = `${s1}${s2}`; this.complete(this.render); this.cursor = this.cursor - 1; this.render(); } deleteForward() { if (this.cursor * this.scale >= this.rendered.length) return this.bell(); let s1 = this.input.slice(0, this.cursor); let s2 = this.input.slice(this.cursor + 1); this.input = `${s1}${s2}`; this.complete(this.render); this.render(); } first() { this.moveSelect(0); this.render(); } last() { this.moveSelect(this.suggestions.length - 1); this.render(); } up() { if (this.select === 0) { this.moveSelect(this.suggestions.length - 1); } else { this.moveSelect(this.select - 1); } this.render(); } down() { if (this.select === this.suggestions.length - 1) { this.moveSelect(0); } else { this.moveSelect(this.select + 1); } this.render(); } next() { if (this.select === this.suggestions.length - 1) { this.moveSelect(0); } else this.moveSelect(this.select + 1); this.render(); } nextPage() { this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1)); this.render(); } prevPage() { this.moveSelect(Math.max(this.select - this.limit, 0)); this.render(); } left() { if (this.cursor <= 0) return this.bell(); this.cursor = this.cursor - 1; this.render(); } right() { if (this.cursor * this.scale >= this.rendered.length) return this.bell(); this.cursor = this.cursor + 1; this.render(); } renderOption(v, hovered, isStart, isEnd) { let desc; let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : ' '; let title = hovered ? color.cyan().underline(v.title) : v.title; prefix = (hovered ? color.cyan(figures.pointer) + ' ' : ' ') + prefix; if (v.description) { desc = ` - ${v.description}`; if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns }); } } return prefix + ' ' + title + color.gray(desc || ''); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns)); super.render(); let _entriesToDisplay = entriesToDisplay(this.select, this.choices.length, this.limit), startIndex = _entriesToDisplay.startIndex, endIndex = _entriesToDisplay.endIndex; this.outputText = [style.symbol(this.done, this.aborted, this.exited), color.bold(this.msg), style.delimiter(this.completing), this.done && this.suggestions[this.select] ? this.suggestions[this.select].title : this.rendered = this.transform.render(this.input)].join(' '); if (!this.done) { const suggestions = this.suggestions.slice(startIndex, endIndex).map((item, i) => this.renderOption(item, this.select === i + startIndex, i === 0 && startIndex > 0, i + startIndex === endIndex - 1 && endIndex < this.choices.length)).join('\n'); this.outputText += `\n` + (suggestions || color.gray(this.fallback.title)); } this.out.write(erase.line + cursor.to(0) + this.outputText); } } autocomplete$1 = AutocompletePrompt; return autocomplete$1; } var autocompleteMultiselect$1; var hasRequiredAutocompleteMultiselect$1; function requireAutocompleteMultiselect$1 () { if (hasRequiredAutocompleteMultiselect$1) return autocompleteMultiselect$1; hasRequiredAutocompleteMultiselect$1 = 1; const color = requireKleur(); const _require = requireSrc(), cursor = _require.cursor; const MultiselectPrompt = requireMultiselect$1(); const _require2 = requireUtil$1(), clear = _require2.clear, style = _require2.style, figures = _require2.figures; /** * MultiselectPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of choice objects * @param {String} [opts.hint] Hint to display * @param {String} [opts.warn] Hint shown for disabled choices * @param {Number} [opts.max] Max choices * @param {Number} [opts.cursor=0] Cursor start position * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class AutocompleteMultiselectPrompt extends MultiselectPrompt { constructor(opts = {}) { opts.overrideRender = true; super(opts); this.inputValue = ''; this.clear = clear('', this.out.columns); this.filteredOptions = this.value; this.render(); } last() { this.cursor = this.filteredOptions.length - 1; this.render(); } next() { this.cursor = (this.cursor + 1) % this.filteredOptions.length; this.render(); } up() { if (this.cursor === 0) { this.cursor = this.filteredOptions.length - 1; } else { this.cursor--; } this.render(); } down() { if (this.cursor === this.filteredOptions.length - 1) { this.cursor = 0; } else { this.cursor++; } this.render(); } left() { this.filteredOptions[this.cursor].selected = false; this.render(); } right() { if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell(); this.filteredOptions[this.cursor].selected = true; this.render(); } delete() { if (this.inputValue.length) { this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1); this.updateFilteredOptions(); } } updateFilteredOptions() { const currentHighlight = this.filteredOptions[this.cursor]; this.filteredOptions = this.value.filter(v => { if (this.inputValue) { if (typeof v.title === 'string') { if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) { return true; } } if (typeof v.value === 'string') { if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) { return true; } } return false; } return true; }); const newHighlightIndex = this.filteredOptions.findIndex(v => v === currentHighlight); this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex; this.render(); } handleSpaceToggle() { const v = this.filteredOptions[this.cursor]; if (v.selected) { v.selected = false; this.render(); } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) { return this.bell(); } else { v.selected = true; this.render(); } } handleInputChange(c) { this.inputValue = this.inputValue + c; this.updateFilteredOptions(); } _(c, key) { if (c === ' ') { this.handleSpaceToggle(); } else { this.handleInputChange(c); } } renderInstructions() { if (this.instructions === undefined || this.instructions) { if (typeof this.instructions === 'string') { return this.instructions; } return ` Instructions: ${figures.arrowUp}/${figures.arrowDown}: Highlight option ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection [a,b,c]/delete: Filter choices enter/return: Complete answer `; } return ''; } renderCurrentInput() { return ` Filtered results for: ${this.inputValue ? this.inputValue : color.gray('Enter something to filter')}\n`; } renderOption(cursor, v, i) { let title; if (v.disabled) title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);else title = cursor === i ? color.cyan().underline(v.title) : v.title; return (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + title; } renderDoneOrInstructions() { if (this.done) { return this.value.filter(e => e.selected).map(v => v.title).join(', '); } const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()]; if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) { output.push(color.yellow(this.warn)); } return output.join(' '); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); super.render(); // print prompt let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions()].join(' '); if (this.showMinError) { prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`); this.showMinError = false; } prompt += this.renderOptions(this.filteredOptions); this.out.write(this.clear + prompt); this.clear = clear(prompt, this.out.columns); } } autocompleteMultiselect$1 = AutocompleteMultiselectPrompt; return autocompleteMultiselect$1; } var confirm$1; var hasRequiredConfirm$1; function requireConfirm$1 () { if (hasRequiredConfirm$1) return confirm$1; hasRequiredConfirm$1 = 1; const color = requireKleur(); const Prompt = requirePrompt$1(); const _require = requireUtil$1(), style = _require.style, clear = _require.clear; const _require2 = requireSrc(), erase = _require2.erase, cursor = _require2.cursor; /** * ConfirmPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Boolean} [opts.initial] Default value (true/false) * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.yes] The "Yes" label * @param {String} [opts.yesOption] The "Yes" option when choosing between yes/no * @param {String} [opts.no] The "No" label * @param {String} [opts.noOption] The "No" option when choosing between yes/no */ class ConfirmPrompt extends Prompt { constructor(opts = {}) { super(opts); this.msg = opts.message; this.value = opts.initial; this.initialValue = !!opts.initial; this.yesMsg = opts.yes || 'yes'; this.yesOption = opts.yesOption || '(Y/n)'; this.noMsg = opts.no || 'no'; this.noOption = opts.noOption || '(y/N)'; this.render(); } reset() { this.value = this.initialValue; this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { this.value = this.value || false; this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } _(c, key) { if (c.toLowerCase() === 'y') { this.value = true; return this.submit(); } if (c.toLowerCase() === 'n') { this.value = false; return this.submit(); } return this.bell(); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide);else this.out.write(clear(this.outputText, this.out.columns)); super.render(); this.outputText = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.done ? this.value ? this.yesMsg : this.noMsg : color.gray(this.initialValue ? this.yesOption : this.noOption)].join(' '); this.out.write(erase.line + cursor.to(0) + this.outputText); } } confirm$1 = ConfirmPrompt; return confirm$1; } var elements$1; var hasRequiredElements$1; function requireElements$1 () { if (hasRequiredElements$1) return elements$1; hasRequiredElements$1 = 1; elements$1 = { TextPrompt: requireText$1(), SelectPrompt: requireSelect$1(), TogglePrompt: requireToggle$1(), DatePrompt: requireDate$1(), NumberPrompt: requireNumber$1(), MultiselectPrompt: requireMultiselect$1(), AutocompletePrompt: requireAutocomplete$1(), AutocompleteMultiselectPrompt: requireAutocompleteMultiselect$1(), ConfirmPrompt: requireConfirm$1() }; return elements$1; } var hasRequiredPrompts$1; function requirePrompts$1 () { if (hasRequiredPrompts$1) return prompts$2; hasRequiredPrompts$1 = 1; (function (exports) { const $ = exports; const el = requireElements$1(); const noop = v => v; function toPrompt(type, args, opts = {}) { return new Promise((res, rej) => { const p = new el[type](args); const onAbort = opts.onAbort || noop; const onSubmit = opts.onSubmit || noop; const onExit = opts.onExit || noop; p.on('state', args.onState || noop); p.on('submit', x => res(onSubmit(x))); p.on('exit', x => res(onExit(x))); p.on('abort', x => rej(onAbort(x))); }); } /** * Text prompt * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {function} [args.onState] On state change callback * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.text = args => toPrompt('TextPrompt', args); /** * Password prompt with masked input * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {function} [args.onState] On state change callback * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.password = args => { args.style = 'password'; return $.text(args); }; /** * Prompt where input is invisible, like sudo * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {function} [args.onState] On state change callback * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.invisible = args => { args.style = 'invisible'; return $.text(args); }; /** * Number prompt * @param {string} args.message Prompt message to display * @param {number} args.initial Default number value * @param {function} [args.onState] On state change callback * @param {number} [args.max] Max value * @param {number} [args.min] Min value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {Boolean} [opts.float=false] Parse input as floats * @param {Number} [opts.round=2] Round floats to x decimals * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.number = args => toPrompt('NumberPrompt', args); /** * Date prompt * @param {string} args.message Prompt message to display * @param {number} args.initial Default number value * @param {function} [args.onState] On state change callback * @param {number} [args.max] Max value * @param {number} [args.min] Min value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {Boolean} [opts.float=false] Parse input as floats * @param {Number} [opts.round=2] Round floats to x decimals * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.date = args => toPrompt('DatePrompt', args); /** * Classic yes/no prompt * @param {string} args.message Prompt message to display * @param {boolean} [args.initial=false] Default value * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.confirm = args => toPrompt('ConfirmPrompt', args); /** * List prompt, split intput string by `seperator` * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {string} [args.separator] String separator * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input, in form of an `Array` */ $.list = args => { const sep = args.separator || ','; return toPrompt('TextPrompt', args, { onSubmit: str => str.split(sep).map(s => s.trim()) }); }; /** * Toggle/switch prompt * @param {string} args.message Prompt message to display * @param {boolean} [args.initial=false] Default value * @param {string} [args.active="on"] Text for `active` state * @param {string} [args.inactive="off"] Text for `inactive` state * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.toggle = args => toPrompt('TogglePrompt', args); /** * Interactive select prompt * @param {string} args.message Prompt message to display * @param {Array} args.choices Array of choices objects `[{ title, value }, ...]` * @param {number} [args.initial] Index of default value * @param {String} [args.hint] Hint to display * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.select = args => toPrompt('SelectPrompt', args); /** * Interactive multi-select / autocompleteMultiselect prompt * @param {string} args.message Prompt message to display * @param {Array} args.choices Array of choices objects `[{ title, value, [selected] }, ...]` * @param {number} [args.max] Max select * @param {string} [args.hint] Hint to display user * @param {Number} [args.cursor=0] Cursor start position * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.multiselect = args => { args.choices = [].concat(args.choices || []); const toSelected = items => items.filter(item => item.selected).map(item => item.value); return toPrompt('MultiselectPrompt', args, { onAbort: toSelected, onSubmit: toSelected }); }; $.autocompleteMultiselect = args => { args.choices = [].concat(args.choices || []); const toSelected = items => items.filter(item => item.selected).map(item => item.value); return toPrompt('AutocompleteMultiselectPrompt', args, { onAbort: toSelected, onSubmit: toSelected }); }; const byTitle = (input, choices) => Promise.resolve(choices.filter(item => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase())); /** * Interactive auto-complete prompt * @param {string} args.message Prompt message to display * @param {Array} args.choices Array of auto-complete choices objects `[{ title, value }, ...]` * @param {Function} [args.suggest] Function to filter results based on user input. Defaults to sort by `title` * @param {number} [args.limit=10] Max number of results to show * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {String} [args.initial] Index of the default value * @param {boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input * @param {String} [args.fallback] Fallback message - defaults to initial value * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.autocomplete = args => { args.suggest = args.suggest || byTitle; args.choices = [].concat(args.choices || []); return toPrompt('AutocompletePrompt', args); }; } (prompts$2)); return prompts$2; } var dist; var hasRequiredDist; function requireDist () { if (hasRequiredDist) return dist; hasRequiredDist = 1; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } const prompts = requirePrompts$1(); const passOn = ['suggest', 'format', 'onState', 'validate', 'onRender', 'type']; const noop = () => {}; /** * Prompt for a series of questions * @param {Array|Object} questions Single question object or Array of question objects * @param {Function} [onSubmit] Callback function called on prompt submit * @param {Function} [onCancel] Callback function called on cancel/abort * @returns {Object} Object with values from user input */ function prompt() { return _prompt.apply(this, arguments); } function _prompt() { _prompt = _asyncToGenerator(function* (questions = [], { onSubmit = noop, onCancel = noop } = {}) { const answers = {}; const override = prompt._override || {}; questions = [].concat(questions); let answer, question, quit, name, type, lastPrompt; const getFormattedAnswer = /*#__PURE__*/function () { var _ref = _asyncToGenerator(function* (question, answer, skipValidation = false) { if (!skipValidation && question.validate && question.validate(answer) !== true) { return; } return question.format ? yield question.format(answer, answers) : answer; }); return function getFormattedAnswer(_x, _x2) { return _ref.apply(this, arguments); }; }(); var _iterator = _createForOfIteratorHelper(questions), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { question = _step.value; var _question = question; name = _question.name; type = _question.type; // evaluate type first and skip if type is a falsy value if (typeof type === 'function') { type = yield type(answer, _objectSpread({}, answers), question); question['type'] = type; } if (!type) continue; // if property is a function, invoke it unless it's a special function for (let key in question) { if (passOn.includes(key)) continue; let value = question[key]; question[key] = typeof value === 'function' ? yield value(answer, _objectSpread({}, answers), lastPrompt) : value; } lastPrompt = question; if (typeof question.message !== 'string') { throw new Error('prompt message is required'); } // update vars in case they changed var _question2 = question; name = _question2.name; type = _question2.type; if (prompts[type] === void 0) { throw new Error(`prompt type (${type}) is not defined`); } if (override[question.name] !== undefined) { answer = yield getFormattedAnswer(question, override[question.name]); if (answer !== undefined) { answers[name] = answer; continue; } } try { // Get the injected answer if there is one or prompt the user answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts[type](question); answers[name] = answer = yield getFormattedAnswer(question, answer, true); quit = yield onSubmit(question, answer, answers); } catch (err) { quit = !(yield onCancel(question, answers)); } if (quit) return answers; } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return answers; }); return _prompt.apply(this, arguments); } function getInjectedAnswer(injected, deafultValue) { const answer = injected.shift(); if (answer instanceof Error) { throw answer; } return answer === undefined ? deafultValue : answer; } function inject(answers) { prompt._injected = (prompt._injected || []).concat(answers); } function override(answers) { prompt._override = Object.assign({}, answers); } dist = Object.assign(prompt, { prompt, prompts, inject, override }); return dist; } var prompts$1 = {}; var action; var hasRequiredAction; function requireAction () { if (hasRequiredAction) return action; hasRequiredAction = 1; action = (key, isSelect) => { if (key.meta && key.name !== 'escape') return; if (key.ctrl) { if (key.name === 'a') return 'first'; if (key.name === 'c') return 'abort'; if (key.name === 'd') return 'abort'; if (key.name === 'e') return 'last'; if (key.name === 'g') return 'reset'; } if (isSelect) { if (key.name === 'j') return 'down'; if (key.name === 'k') return 'up'; } if (key.name === 'return') return 'submit'; if (key.name === 'enter') return 'submit'; // ctrl + J if (key.name === 'backspace') return 'delete'; if (key.name === 'delete') return 'deleteForward'; if (key.name === 'abort') return 'abort'; if (key.name === 'escape') return 'exit'; if (key.name === 'tab') return 'next'; if (key.name === 'pagedown') return 'nextPage'; if (key.name === 'pageup') return 'prevPage'; // TODO create home() in prompt types (e.g. TextPrompt) if (key.name === 'home') return 'home'; // TODO create end() in prompt types (e.g. TextPrompt) if (key.name === 'end') return 'end'; if (key.name === 'up') return 'up'; if (key.name === 'down') return 'down'; if (key.name === 'right') return 'right'; if (key.name === 'left') return 'left'; return false; }; return action; } var strip; var hasRequiredStrip; function requireStrip () { if (hasRequiredStrip) return strip; hasRequiredStrip = 1; strip = str => { const pattern = [ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))' ].join('|'); const RGX = new RegExp(pattern, 'g'); return typeof str === 'string' ? str.replace(RGX, '') : str; }; return strip; } var clear; var hasRequiredClear; function requireClear () { if (hasRequiredClear) return clear; hasRequiredClear = 1; const strip = requireStrip(); const { erase, cursor } = requireSrc(); const width = str => [...strip(str)].length; /** * @param {string} prompt * @param {number} perLine */ clear = function(prompt, perLine) { if (!perLine) return erase.line + cursor.to(0); let rows = 0; const lines = prompt.split(/\r?\n/); for (let line of lines) { rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine); } return erase.lines(rows); }; return clear; } var figures_1; var hasRequiredFigures; function requireFigures () { if (hasRequiredFigures) return figures_1; hasRequiredFigures = 1; const main = { arrowUp: '↑', arrowDown: '↓', arrowLeft: '←', arrowRight: '→', radioOn: '◉', radioOff: '◯', tick: '✔', cross: '✖', ellipsis: '…', pointerSmall: '›', line: '─', pointer: '❯' }; const win = { arrowUp: main.arrowUp, arrowDown: main.arrowDown, arrowLeft: main.arrowLeft, arrowRight: main.arrowRight, radioOn: '(*)', radioOff: '( )', tick: '√', cross: '×', ellipsis: '...', pointerSmall: '»', line: '─', pointer: '>' }; const figures = process.platform === 'win32' ? win : main; figures_1 = figures; return figures_1; } var style; var hasRequiredStyle; function requireStyle () { if (hasRequiredStyle) return style; hasRequiredStyle = 1; const c = requireKleur(); const figures = requireFigures(); // rendering user input. const styles = Object.freeze({ password: { scale: 1, render: input => '*'.repeat(input.length) }, emoji: { scale: 2, render: input => '😃'.repeat(input.length) }, invisible: { scale: 0, render: input => '' }, default: { scale: 1, render: input => `${input}` } }); const render = type => styles[type] || styles.default; // icon to signalize a prompt. const symbols = Object.freeze({ aborted: c.red(figures.cross), done: c.green(figures.tick), exited: c.yellow(figures.cross), default: c.cyan('?') }); const symbol = (done, aborted, exited) => aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default; // between the question and the user's input. const delimiter = completing => c.gray(completing ? figures.ellipsis : figures.pointerSmall); const item = (expandable, expanded) => c.gray(expandable ? (expanded ? figures.pointerSmall : '+') : figures.line); style = { styles, render, symbols, symbol, delimiter, item }; return style; } var lines; var hasRequiredLines; function requireLines () { if (hasRequiredLines) return lines; hasRequiredLines = 1; const strip = requireStrip(); /** * @param {string} msg * @param {number} perLine */ lines = function (msg, perLine) { let lines = String(strip(msg) || '').split(/\r?\n/); if (!perLine) return lines.length; return lines.map(l => Math.ceil(l.length / perLine)) .reduce((a, b) => a + b); }; return lines; } var wrap; var hasRequiredWrap; function requireWrap () { if (hasRequiredWrap) return wrap; hasRequiredWrap = 1; /** * @param {string} msg The message to wrap * @param {object} opts * @param {number|string} [opts.margin] Left margin * @param {number} opts.width Maximum characters per line including the margin */ wrap = (msg, opts = {}) => { const tab = Number.isSafeInteger(parseInt(opts.margin)) ? new Array(parseInt(opts.margin)).fill(' ').join('') : (opts.margin || ''); const width = opts.width; return (msg || '').split(/\r?\n/g) .map(line => line .split(/\s+/g) .reduce((arr, w) => { if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width) arr[arr.length - 1] += ` ${w}`; else arr.push(`${tab}${w}`); return arr; }, [ tab ]) .join('\n')) .join('\n'); }; return wrap; } var entriesToDisplay; var hasRequiredEntriesToDisplay; function requireEntriesToDisplay () { if (hasRequiredEntriesToDisplay) return entriesToDisplay; hasRequiredEntriesToDisplay = 1; /** * Determine what entries should be displayed on the screen, based on the * currently selected index and the maximum visible. Used in list-based * prompts like `select` and `multiselect`. * * @param {number} cursor the currently selected entry * @param {number} total the total entries available to display * @param {number} [maxVisible] the number of entries that can be displayed */ entriesToDisplay = (cursor, total, maxVisible) => { maxVisible = maxVisible || total; let startIndex = Math.min(total- maxVisible, cursor - Math.floor(maxVisible / 2)); if (startIndex < 0) startIndex = 0; let endIndex = Math.min(startIndex + maxVisible, total); return { startIndex, endIndex }; }; return entriesToDisplay; } var util; var hasRequiredUtil; function requireUtil () { if (hasRequiredUtil) return util; hasRequiredUtil = 1; util = { action: requireAction(), clear: requireClear(), style: requireStyle(), strip: requireStrip(), figures: requireFigures(), lines: requireLines(), wrap: requireWrap(), entriesToDisplay: requireEntriesToDisplay() }; return util; } var prompt$1; var hasRequiredPrompt; function requirePrompt () { if (hasRequiredPrompt) return prompt$1; hasRequiredPrompt = 1; const readline = require$$0$6; const { action } = requireUtil(); const EventEmitter = require$$0$3; const { beep, cursor } = requireSrc(); const color = requireKleur(); /** * Base prompt skeleton * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class Prompt extends EventEmitter { constructor(opts={}) { super(); this.firstRender = true; this.in = opts.stdin || process.stdin; this.out = opts.stdout || process.stdout; this.onRender = (opts.onRender || (() => void 0)).bind(this); const rl = readline.createInterface({ input:this.in, escapeCodeTimeout:50 }); readline.emitKeypressEvents(this.in, rl); if (this.in.isTTY) this.in.setRawMode(true); const isSelect = [ 'SelectPrompt', 'MultiselectPrompt' ].indexOf(this.constructor.name) > -1; const keypress = (str, key) => { let a = action(key, isSelect); if (a === false) { this._ && this._(str, key); } else if (typeof this[a] === 'function') { this[a](key); } else { this.bell(); } }; this.close = () => { this.out.write(cursor.show); this.in.removeListener('keypress', keypress); if (this.in.isTTY) this.in.setRawMode(false); rl.close(); this.emit(this.aborted ? 'abort' : this.exited ? 'exit' : 'submit', this.value); this.closed = true; }; this.in.on('keypress', keypress); } fire() { this.emit('state', { value: this.value, aborted: !!this.aborted, exited: !!this.exited }); } bell() { this.out.write(beep); } render() { this.onRender(color); if (this.firstRender) this.firstRender = false; } } prompt$1 = Prompt; return prompt$1; } var text; var hasRequiredText; function requireText () { if (hasRequiredText) return text; hasRequiredText = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { erase, cursor } = requireSrc(); const { style, clear, lines, figures } = requireUtil(); /** * TextPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {String} [opts.style='default'] Render style * @param {String} [opts.initial] Default value * @param {Function} [opts.validate] Validate function * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.error] The invalid error label */ class TextPrompt extends Prompt { constructor(opts={}) { super(opts); this.transform = style.render(opts.style); this.scale = this.transform.scale; this.msg = opts.message; this.initial = opts.initial || ``; this.validator = opts.validate || (() => true); this.value = ``; this.errorMsg = opts.error || `Please Enter A Valid Value`; this.cursor = Number(!!this.initial); this.cursorOffset = 0; this.clear = clear(``, this.out.columns); this.render(); } set value(v) { if (!v && this.initial) { this.placeholder = true; this.rendered = color.gray(this.transform.render(this.initial)); } else { this.placeholder = false; this.rendered = this.transform.render(v); } this._value = v; this.fire(); } get value() { return this._value; } reset() { this.value = ``; this.cursor = Number(!!this.initial); this.cursorOffset = 0; this.fire(); this.render(); } exit() { this.abort(); } abort() { this.value = this.value || this.initial; this.done = this.aborted = true; this.error = false; this.red = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } async validate() { let valid = await this.validator(this.value); if (typeof valid === `string`) { this.errorMsg = valid; valid = false; } this.error = !valid; } async submit() { this.value = this.value || this.initial; this.cursorOffset = 0; this.cursor = this.rendered.length; await this.validate(); if (this.error) { this.red = true; this.fire(); this.render(); return; } this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } next() { if (!this.placeholder) return this.bell(); this.value = this.initial; this.cursor = this.rendered.length; this.fire(); this.render(); } moveCursor(n) { if (this.placeholder) return; this.cursor = this.cursor+n; this.cursorOffset += n; } _(c, key) { let s1 = this.value.slice(0, this.cursor); let s2 = this.value.slice(this.cursor); this.value = `${s1}${c}${s2}`; this.red = false; this.cursor = this.placeholder ? 0 : s1.length+1; this.render(); } delete() { if (this.isCursorAtStart()) return this.bell(); let s1 = this.value.slice(0, this.cursor-1); let s2 = this.value.slice(this.cursor); this.value = `${s1}${s2}`; this.red = false; if (this.isCursorAtStart()) { this.cursorOffset = 0; } else { this.cursorOffset++; this.moveCursor(-1); } this.render(); } deleteForward() { if(this.cursor*this.scale >= this.rendered.length || this.placeholder) return this.bell(); let s1 = this.value.slice(0, this.cursor); let s2 = this.value.slice(this.cursor+1); this.value = `${s1}${s2}`; this.red = false; if (this.isCursorAtEnd()) { this.cursorOffset = 0; } else { this.cursorOffset++; } this.render(); } first() { this.cursor = 0; this.render(); } last() { this.cursor = this.value.length; this.render(); } left() { if (this.cursor <= 0 || this.placeholder) return this.bell(); this.moveCursor(-1); this.render(); } right() { if (this.cursor*this.scale >= this.rendered.length || this.placeholder) return this.bell(); this.moveCursor(1); this.render(); } isCursorAtStart() { return this.cursor === 0 || (this.placeholder && this.cursor === 1); } isCursorAtEnd() { return this.cursor === this.rendered.length || (this.placeholder && this.cursor === this.rendered.length + 1) } render() { if (this.closed) return; if (!this.firstRender) { if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns)); this.out.write(clear(this.outputText, this.out.columns)); } super.render(); this.outputError = ''; this.outputText = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.red ? color.red(this.rendered) : this.rendered ].join(` `); if (this.error) { this.outputError += this.errorMsg.split(`\n`) .reduce((a, l, i) => a + `\n${i ? ' ' : figures.pointerSmall} ${color.red().italic(l)}`, ``); } this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0)); } } text = TextPrompt; return text; } var select; var hasRequiredSelect; function requireSelect () { if (hasRequiredSelect) return select; hasRequiredSelect = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { style, clear, figures, wrap, entriesToDisplay } = requireUtil(); const { cursor } = requireSrc(); /** * SelectPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of choice objects * @param {String} [opts.hint] Hint to display * @param {Number} [opts.initial] Index of default value * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {Number} [opts.optionsPerPage=10] Max options to display at once */ class SelectPrompt extends Prompt { constructor(opts={}) { super(opts); this.msg = opts.message; this.hint = opts.hint || '- Use arrow-keys. Return to submit.'; this.warn = opts.warn || '- This option is disabled'; this.cursor = opts.initial || 0; this.choices = opts.choices.map((ch, idx) => { if (typeof ch === 'string') ch = {title: ch, value: idx}; return { title: ch && (ch.title || ch.value || ch), value: ch && (ch.value === undefined ? idx : ch.value), description: ch && ch.description, selected: ch && ch.selected, disabled: ch && ch.disabled }; }); this.optionsPerPage = opts.optionsPerPage || 10; this.value = (this.choices[this.cursor] || {}).value; this.clear = clear('', this.out.columns); this.render(); } moveCursor(n) { this.cursor = n; this.value = this.choices[n].value; this.fire(); } reset() { this.moveCursor(0); this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { if (!this.selection.disabled) { this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } else this.bell(); } first() { this.moveCursor(0); this.render(); } last() { this.moveCursor(this.choices.length - 1); this.render(); } up() { if (this.cursor === 0) { this.moveCursor(this.choices.length - 1); } else { this.moveCursor(this.cursor - 1); } this.render(); } down() { if (this.cursor === this.choices.length - 1) { this.moveCursor(0); } else { this.moveCursor(this.cursor + 1); } this.render(); } next() { this.moveCursor((this.cursor + 1) % this.choices.length); this.render(); } _(c, key) { if (c === ' ') return this.submit(); } get selection() { return this.choices[this.cursor]; } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); else this.out.write(clear(this.outputText, this.out.columns)); super.render(); let { startIndex, endIndex } = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage); // Print prompt this.outputText = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.done ? this.selection.title : this.selection.disabled ? color.yellow(this.warn) : color.gray(this.hint) ].join(' '); // Print choices if (!this.done) { this.outputText += '\n'; for (let i = startIndex; i < endIndex; i++) { let title, prefix, desc = '', v = this.choices[i]; // Determine whether to display "more choices" indicators if (i === startIndex && startIndex > 0) { prefix = figures.arrowUp; } else if (i === endIndex - 1 && endIndex < this.choices.length) { prefix = figures.arrowDown; } else { prefix = ' '; } if (v.disabled) { title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title); prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + ' ' : ' ') + prefix; } else { title = this.cursor === i ? color.cyan().underline(v.title) : v.title; prefix = (this.cursor === i ? color.cyan(figures.pointer) + ' ' : ' ') + prefix; if (v.description && this.cursor === i) { desc = ` - ${v.description}`; if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns }); } } } this.outputText += `${prefix} ${title}${color.gray(desc)}\n`; } } this.out.write(this.outputText); } } select = SelectPrompt; return select; } var toggle; var hasRequiredToggle; function requireToggle () { if (hasRequiredToggle) return toggle; hasRequiredToggle = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { style, clear } = requireUtil(); const { cursor, erase } = requireSrc(); /** * TogglePrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Boolean} [opts.initial=false] Default value * @param {String} [opts.active='no'] Active label * @param {String} [opts.inactive='off'] Inactive label * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class TogglePrompt extends Prompt { constructor(opts={}) { super(opts); this.msg = opts.message; this.value = !!opts.initial; this.active = opts.active || 'on'; this.inactive = opts.inactive || 'off'; this.initialValue = this.value; this.render(); } reset() { this.value = this.initialValue; this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } deactivate() { if (this.value === false) return this.bell(); this.value = false; this.render(); } activate() { if (this.value === true) return this.bell(); this.value = true; this.render(); } delete() { this.deactivate(); } left() { this.deactivate(); } right() { this.activate(); } down() { this.deactivate(); } up() { this.activate(); } next() { this.value = !this.value; this.fire(); this.render(); } _(c, key) { if (c === ' ') { this.value = !this.value; } else if (c === '1') { this.value = true; } else if (c === '0') { this.value = false; } else return this.bell(); this.render(); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); else this.out.write(clear(this.outputText, this.out.columns)); super.render(); this.outputText = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.value ? this.inactive : color.cyan().underline(this.inactive), color.gray('/'), this.value ? color.cyan().underline(this.active) : this.active ].join(' '); this.out.write(erase.line + cursor.to(0) + this.outputText); } } toggle = TogglePrompt; return toggle; } var datepart; var hasRequiredDatepart; function requireDatepart () { if (hasRequiredDatepart) return datepart; hasRequiredDatepart = 1; class DatePart { constructor({token, date, parts, locales}) { this.token = token; this.date = date || new Date(); this.parts = parts || [this]; this.locales = locales || {}; } up() {} down() {} next() { const currentIdx = this.parts.indexOf(this); return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart); } setTo(val) {} prev() { let parts = [].concat(this.parts).reverse(); const currentIdx = parts.indexOf(this); return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart); } toString() { return String(this.date); } } datepart = DatePart; return datepart; } var meridiem; var hasRequiredMeridiem; function requireMeridiem () { if (hasRequiredMeridiem) return meridiem; hasRequiredMeridiem = 1; const DatePart = requireDatepart(); class Meridiem extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setHours((this.date.getHours() + 12) % 24); } down() { this.up(); } toString() { let meridiem = this.date.getHours() > 12 ? 'pm' : 'am'; return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem; } } meridiem = Meridiem; return meridiem; } var day; var hasRequiredDay; function requireDay () { if (hasRequiredDay) return day; hasRequiredDay = 1; const DatePart = requireDatepart(); const pos = n => { n = n % 10; return n === 1 ? 'st' : n === 2 ? 'nd' : n === 3 ? 'rd' : 'th'; }; class Day extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setDate(this.date.getDate() + 1); } down() { this.date.setDate(this.date.getDate() - 1); } setTo(val) { this.date.setDate(parseInt(val.substr(-2))); } toString() { let date = this.date.getDate(); let day = this.date.getDay(); return this.token === 'DD' ? String(date).padStart(2, '0') : this.token === 'Do' ? date + pos(date) : this.token === 'd' ? day + 1 : this.token === 'ddd' ? this.locales.weekdaysShort[day] : this.token === 'dddd' ? this.locales.weekdays[day] : date; } } day = Day; return day; } var hours; var hasRequiredHours; function requireHours () { if (hasRequiredHours) return hours; hasRequiredHours = 1; const DatePart = requireDatepart(); class Hours extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setHours(this.date.getHours() + 1); } down() { this.date.setHours(this.date.getHours() - 1); } setTo(val) { this.date.setHours(parseInt(val.substr(-2))); } toString() { let hours = this.date.getHours(); if (/h/.test(this.token)) hours = (hours % 12) || 12; return this.token.length > 1 ? String(hours).padStart(2, '0') : hours; } } hours = Hours; return hours; } var milliseconds; var hasRequiredMilliseconds; function requireMilliseconds () { if (hasRequiredMilliseconds) return milliseconds; hasRequiredMilliseconds = 1; const DatePart = requireDatepart(); class Milliseconds extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setMilliseconds(this.date.getMilliseconds() + 1); } down() { this.date.setMilliseconds(this.date.getMilliseconds() - 1); } setTo(val) { this.date.setMilliseconds(parseInt(val.substr(-(this.token.length)))); } toString() { return String(this.date.getMilliseconds()).padStart(4, '0') .substr(0, this.token.length); } } milliseconds = Milliseconds; return milliseconds; } var minutes; var hasRequiredMinutes; function requireMinutes () { if (hasRequiredMinutes) return minutes; hasRequiredMinutes = 1; const DatePart = requireDatepart(); class Minutes extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setMinutes(this.date.getMinutes() + 1); } down() { this.date.setMinutes(this.date.getMinutes() - 1); } setTo(val) { this.date.setMinutes(parseInt(val.substr(-2))); } toString() { let m = this.date.getMinutes(); return this.token.length > 1 ? String(m).padStart(2, '0') : m; } } minutes = Minutes; return minutes; } var month; var hasRequiredMonth; function requireMonth () { if (hasRequiredMonth) return month; hasRequiredMonth = 1; const DatePart = requireDatepart(); class Month extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setMonth(this.date.getMonth() + 1); } down() { this.date.setMonth(this.date.getMonth() - 1); } setTo(val) { val = parseInt(val.substr(-2)) - 1; this.date.setMonth(val < 0 ? 0 : val); } toString() { let month = this.date.getMonth(); let tl = this.token.length; return tl === 2 ? String(month + 1).padStart(2, '0') : tl === 3 ? this.locales.monthsShort[month] : tl === 4 ? this.locales.months[month] : String(month + 1); } } month = Month; return month; } var seconds; var hasRequiredSeconds; function requireSeconds () { if (hasRequiredSeconds) return seconds; hasRequiredSeconds = 1; const DatePart = requireDatepart(); class Seconds extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setSeconds(this.date.getSeconds() + 1); } down() { this.date.setSeconds(this.date.getSeconds() - 1); } setTo(val) { this.date.setSeconds(parseInt(val.substr(-2))); } toString() { let s = this.date.getSeconds(); return this.token.length > 1 ? String(s).padStart(2, '0') : s; } } seconds = Seconds; return seconds; } var year; var hasRequiredYear; function requireYear () { if (hasRequiredYear) return year; hasRequiredYear = 1; const DatePart = requireDatepart(); class Year extends DatePart { constructor(opts={}) { super(opts); } up() { this.date.setFullYear(this.date.getFullYear() + 1); } down() { this.date.setFullYear(this.date.getFullYear() - 1); } setTo(val) { this.date.setFullYear(val.substr(-4)); } toString() { let year = String(this.date.getFullYear()).padStart(4, '0'); return this.token.length === 2 ? year.substr(-2) : year; } } year = Year; return year; } var dateparts; var hasRequiredDateparts; function requireDateparts () { if (hasRequiredDateparts) return dateparts; hasRequiredDateparts = 1; dateparts = { DatePart: requireDatepart(), Meridiem: requireMeridiem(), Day: requireDay(), Hours: requireHours(), Milliseconds: requireMilliseconds(), Minutes: requireMinutes(), Month: requireMonth(), Seconds: requireSeconds(), Year: requireYear(), }; return dateparts; } var date; var hasRequiredDate; function requireDate () { if (hasRequiredDate) return date; hasRequiredDate = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { style, clear, figures } = requireUtil(); const { erase, cursor } = requireSrc(); const { DatePart, Meridiem, Day, Hours, Milliseconds, Minutes, Month, Seconds, Year } = requireDateparts(); const regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g; const regexGroups = { 1: ({token}) => token.replace(/\\(.)/g, '$1'), 2: (opts) => new Day(opts), // Day // TODO 3: (opts) => new Month(opts), // Month 4: (opts) => new Year(opts), // Year 5: (opts) => new Meridiem(opts), // AM/PM // TODO (special) 6: (opts) => new Hours(opts), // Hours 7: (opts) => new Minutes(opts), // Minutes 8: (opts) => new Seconds(opts), // Seconds 9: (opts) => new Milliseconds(opts), // Fractional seconds }; const dfltLocales = { months: 'January,February,March,April,May,June,July,August,September,October,November,December'.split(','), monthsShort: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','), weekdays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','), weekdaysShort: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(',') }; /** * DatePrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Number} [opts.initial] Index of default value * @param {String} [opts.mask] The format mask * @param {object} [opts.locales] The date locales * @param {String} [opts.error] The error message shown on invalid value * @param {Function} [opts.validate] Function to validate the submitted value * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class DatePrompt extends Prompt { constructor(opts={}) { super(opts); this.msg = opts.message; this.cursor = 0; this.typed = ''; this.locales = Object.assign(dfltLocales, opts.locales); this._date = opts.initial || new Date(); this.errorMsg = opts.error || 'Please Enter A Valid Value'; this.validator = opts.validate || (() => true); this.mask = opts.mask || 'YYYY-MM-DD HH:mm:ss'; this.clear = clear('', this.out.columns); this.render(); } get value() { return this.date } get date() { return this._date; } set date(date) { if (date) this._date.setTime(date.getTime()); } set mask(mask) { let result; this.parts = []; while(result = regex.exec(mask)) { let match = result.shift(); let idx = result.findIndex(gr => gr != null); this.parts.push(idx in regexGroups ? regexGroups[idx]({ token: result[idx] || match, date: this.date, parts: this.parts, locales: this.locales }) : result[idx] || match); } let parts = this.parts.reduce((arr, i) => { if (typeof i === 'string' && typeof arr[arr.length - 1] === 'string') arr[arr.length - 1] += i; else arr.push(i); return arr; }, []); this.parts.splice(0); this.parts.push(...parts); this.reset(); } moveCursor(n) { this.typed = ''; this.cursor = n; this.fire(); } reset() { this.moveCursor(this.parts.findIndex(p => p instanceof DatePart)); this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.error = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } async validate() { let valid = await this.validator(this.value); if (typeof valid === 'string') { this.errorMsg = valid; valid = false; } this.error = !valid; } async submit() { await this.validate(); if (this.error) { this.color = 'red'; this.fire(); this.render(); return; } this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } up() { this.typed = ''; this.parts[this.cursor].up(); this.render(); } down() { this.typed = ''; this.parts[this.cursor].down(); this.render(); } left() { let prev = this.parts[this.cursor].prev(); if (prev == null) return this.bell(); this.moveCursor(this.parts.indexOf(prev)); this.render(); } right() { let next = this.parts[this.cursor].next(); if (next == null) return this.bell(); this.moveCursor(this.parts.indexOf(next)); this.render(); } next() { let next = this.parts[this.cursor].next(); this.moveCursor(next ? this.parts.indexOf(next) : this.parts.findIndex((part) => part instanceof DatePart)); this.render(); } _(c) { if (/\d/.test(c)) { this.typed += c; this.parts[this.cursor].setTo(this.typed); this.render(); } } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); else this.out.write(clear(this.outputText, this.out.columns)); super.render(); // Print prompt this.outputText = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), []) .join('') ].join(' '); // Print error if (this.error) { this.outputText += this.errorMsg.split('\n').reduce( (a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``); } this.out.write(erase.line + cursor.to(0) + this.outputText); } } date = DatePrompt; return date; } var number; var hasRequiredNumber; function requireNumber () { if (hasRequiredNumber) return number; hasRequiredNumber = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { cursor, erase } = requireSrc(); const { style, figures, clear, lines } = requireUtil(); const isNumber = /[0-9]/; const isDef = any => any !== undefined; const round = (number, precision) => { let factor = Math.pow(10, precision); return Math.round(number * factor) / factor; }; /** * NumberPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {String} [opts.style='default'] Render style * @param {Number} [opts.initial] Default value * @param {Number} [opts.max=+Infinity] Max value * @param {Number} [opts.min=-Infinity] Min value * @param {Boolean} [opts.float=false] Parse input as floats * @param {Number} [opts.round=2] Round floats to x decimals * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys * @param {Function} [opts.validate] Validate function * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.error] The invalid error label */ class NumberPrompt extends Prompt { constructor(opts={}) { super(opts); this.transform = style.render(opts.style); this.msg = opts.message; this.initial = isDef(opts.initial) ? opts.initial : ''; this.float = !!opts.float; this.round = opts.round || 2; this.inc = opts.increment || 1; this.min = isDef(opts.min) ? opts.min : -Infinity; this.max = isDef(opts.max) ? opts.max : Infinity; this.errorMsg = opts.error || `Please Enter A Valid Value`; this.validator = opts.validate || (() => true); this.color = `cyan`; this.value = ``; this.typed = ``; this.lastHit = 0; this.render(); } set value(v) { if (!v && v !== 0) { this.placeholder = true; this.rendered = color.gray(this.transform.render(`${this.initial}`)); this._value = ``; } else { this.placeholder = false; this.rendered = this.transform.render(`${round(v, this.round)}`); this._value = round(v, this.round); } this.fire(); } get value() { return this._value; } parse(x) { return this.float ? parseFloat(x) : parseInt(x); } valid(c) { return c === `-` || c === `.` && this.float || isNumber.test(c) } reset() { this.typed = ``; this.value = ``; this.fire(); this.render(); } exit() { this.abort(); } abort() { let x = this.value; this.value = x !== `` ? x : this.initial; this.done = this.aborted = true; this.error = false; this.fire(); this.render(); this.out.write(`\n`); this.close(); } async validate() { let valid = await this.validator(this.value); if (typeof valid === `string`) { this.errorMsg = valid; valid = false; } this.error = !valid; } async submit() { await this.validate(); if (this.error) { this.color = `red`; this.fire(); this.render(); return; } let x = this.value; this.value = x !== `` ? x : this.initial; this.done = true; this.aborted = false; this.error = false; this.fire(); this.render(); this.out.write(`\n`); this.close(); } up() { this.typed = ``; if(this.value === '') { this.value = this.min - this.inc; } if (this.value >= this.max) return this.bell(); this.value += this.inc; this.color = `cyan`; this.fire(); this.render(); } down() { this.typed = ``; if(this.value === '') { this.value = this.min + this.inc; } if (this.value <= this.min) return this.bell(); this.value -= this.inc; this.color = `cyan`; this.fire(); this.render(); } delete() { let val = this.value.toString(); if (val.length === 0) return this.bell(); this.value = this.parse((val = val.slice(0, -1))) || ``; if (this.value !== '' && this.value < this.min) { this.value = this.min; } this.color = `cyan`; this.fire(); this.render(); } next() { this.value = this.initial; this.fire(); this.render(); } _(c, key) { if (!this.valid(c)) return this.bell(); const now = Date.now(); if (now - this.lastHit > 1000) this.typed = ``; // 1s elapsed this.typed += c; this.lastHit = now; this.color = `cyan`; if (c === `.`) return this.fire(); this.value = Math.min(this.parse(this.typed), this.max); if (this.value > this.max) this.value = this.max; if (this.value < this.min) this.value = this.min; this.fire(); this.render(); } render() { if (this.closed) return; if (!this.firstRender) { if (this.outputError) this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns)); this.out.write(clear(this.outputText, this.out.columns)); } super.render(); this.outputError = ''; // Print prompt this.outputText = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), !this.done || (!this.done && !this.placeholder) ? color[this.color]().underline(this.rendered) : this.rendered ].join(` `); // Print error if (this.error) { this.outputError += this.errorMsg.split(`\n`) .reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``); } this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore); } } number = NumberPrompt; return number; } var multiselect; var hasRequiredMultiselect; function requireMultiselect () { if (hasRequiredMultiselect) return multiselect; hasRequiredMultiselect = 1; const color = requireKleur(); const { cursor } = requireSrc(); const Prompt = requirePrompt(); const { clear, figures, style, wrap, entriesToDisplay } = requireUtil(); /** * MultiselectPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of choice objects * @param {String} [opts.hint] Hint to display * @param {String} [opts.warn] Hint shown for disabled choices * @param {Number} [opts.max] Max choices * @param {Number} [opts.cursor=0] Cursor start position * @param {Number} [opts.optionsPerPage=10] Max options to display at once * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class MultiselectPrompt extends Prompt { constructor(opts={}) { super(opts); this.msg = opts.message; this.cursor = opts.cursor || 0; this.scrollIndex = opts.cursor || 0; this.hint = opts.hint || ''; this.warn = opts.warn || '- This option is disabled -'; this.minSelected = opts.min; this.showMinError = false; this.maxChoices = opts.max; this.instructions = opts.instructions; this.optionsPerPage = opts.optionsPerPage || 10; this.value = opts.choices.map((ch, idx) => { if (typeof ch === 'string') ch = {title: ch, value: idx}; return { title: ch && (ch.title || ch.value || ch), description: ch && ch.description, value: ch && (ch.value === undefined ? idx : ch.value), selected: ch && ch.selected, disabled: ch && ch.disabled }; }); this.clear = clear('', this.out.columns); if (!opts.overrideRender) { this.render(); } } reset() { this.value.map(v => !v.selected); this.cursor = 0; this.fire(); this.render(); } selected() { return this.value.filter(v => v.selected); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { const selected = this.value .filter(e => e.selected); if (this.minSelected && selected.length < this.minSelected) { this.showMinError = true; this.render(); } else { this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } } first() { this.cursor = 0; this.render(); } last() { this.cursor = this.value.length - 1; this.render(); } next() { this.cursor = (this.cursor + 1) % this.value.length; this.render(); } up() { if (this.cursor === 0) { this.cursor = this.value.length - 1; } else { this.cursor--; } this.render(); } down() { if (this.cursor === this.value.length - 1) { this.cursor = 0; } else { this.cursor++; } this.render(); } left() { this.value[this.cursor].selected = false; this.render(); } right() { if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell(); this.value[this.cursor].selected = true; this.render(); } handleSpaceToggle() { const v = this.value[this.cursor]; if (v.selected) { v.selected = false; this.render(); } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) { return this.bell(); } else { v.selected = true; this.render(); } } toggleAll() { if (this.maxChoices !== undefined || this.value[this.cursor].disabled) { return this.bell(); } const newSelected = !this.value[this.cursor].selected; this.value.filter(v => !v.disabled).forEach(v => v.selected = newSelected); this.render(); } _(c, key) { if (c === ' ') { this.handleSpaceToggle(); } else if (c === 'a') { this.toggleAll(); } else { return this.bell(); } } renderInstructions() { if (this.instructions === undefined || this.instructions) { if (typeof this.instructions === 'string') { return this.instructions; } return '\nInstructions:\n' + ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option\n` + ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection\n` + (this.maxChoices === undefined ? ` a: Toggle all\n` : '') + ` enter/return: Complete answer`; } return ''; } renderOption(cursor, v, i, arrowIndicator) { const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + arrowIndicator + ' '; let title, desc; if (v.disabled) { title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title); } else { title = cursor === i ? color.cyan().underline(v.title) : v.title; if (cursor === i && v.description) { desc = ` - ${v.description}`; if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { desc = '\n' + wrap(v.description, { margin: prefix.length, width: this.out.columns }); } } } return prefix + title + color.gray(desc || ''); } // shared with autocompleteMultiselect paginateOptions(options) { if (options.length === 0) { return color.red('No matches for this query.'); } let { startIndex, endIndex } = entriesToDisplay(this.cursor, options.length, this.optionsPerPage); let prefix, styledOptions = []; for (let i = startIndex; i < endIndex; i++) { if (i === startIndex && startIndex > 0) { prefix = figures.arrowUp; } else if (i === endIndex - 1 && endIndex < options.length) { prefix = figures.arrowDown; } else { prefix = ' '; } styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix)); } return '\n' + styledOptions.join('\n'); } // shared with autocomleteMultiselect renderOptions(options) { if (!this.done) { return this.paginateOptions(options); } return ''; } renderDoneOrInstructions() { if (this.done) { return this.value .filter(e => e.selected) .map(v => v.title) .join(', '); } const output = [color.gray(this.hint), this.renderInstructions()]; if (this.value[this.cursor].disabled) { output.push(color.yellow(this.warn)); } return output.join(' '); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); super.render(); // print prompt let prompt = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions() ].join(' '); if (this.showMinError) { prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`); this.showMinError = false; } prompt += this.renderOptions(this.value); this.out.write(this.clear + prompt); this.clear = clear(prompt, this.out.columns); } } multiselect = MultiselectPrompt; return multiselect; } var autocomplete; var hasRequiredAutocomplete; function requireAutocomplete () { if (hasRequiredAutocomplete) return autocomplete; hasRequiredAutocomplete = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { erase, cursor } = requireSrc(); const { style, clear, figures, wrap, entriesToDisplay } = requireUtil(); const getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]); const getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]); const getIndex = (arr, valOrTitle) => { const index = arr.findIndex(el => el.value === valOrTitle || el.title === valOrTitle); return index > -1 ? index : undefined; }; /** * TextPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of auto-complete choices objects * @param {Function} [opts.suggest] Filter function. Defaults to sort by title * @param {Number} [opts.limit=10] Max number of results to show * @param {Number} [opts.cursor=0] Cursor start position * @param {String} [opts.style='default'] Render style * @param {String} [opts.fallback] Fallback message - initial to default value * @param {String} [opts.initial] Index of the default value * @param {Boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.noMatches] The no matches found label */ class AutocompletePrompt extends Prompt { constructor(opts={}) { super(opts); this.msg = opts.message; this.suggest = opts.suggest; this.choices = opts.choices; this.initial = typeof opts.initial === 'number' ? opts.initial : getIndex(opts.choices, opts.initial); this.select = this.initial || opts.cursor || 0; this.i18n = { noMatches: opts.noMatches || 'no matches found' }; this.fallback = opts.fallback || this.initial; this.clearFirst = opts.clearFirst || false; this.suggestions = []; this.input = ''; this.limit = opts.limit || 10; this.cursor = 0; this.transform = style.render(opts.style); this.scale = this.transform.scale; this.render = this.render.bind(this); this.complete = this.complete.bind(this); this.clear = clear('', this.out.columns); this.complete(this.render); this.render(); } set fallback(fb) { this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb; } get fallback() { let choice; if (typeof this._fb === 'number') choice = this.choices[this._fb]; else if (typeof this._fb === 'string') choice = { title: this._fb }; return choice || this._fb || { title: this.i18n.noMatches }; } moveSelect(i) { this.select = i; if (this.suggestions.length > 0) this.value = getVal(this.suggestions, i); else this.value = this.fallback.value; this.fire(); } async complete(cb) { const p = (this.completing = this.suggest(this.input, this.choices)); const suggestions = await p; if (this.completing !== p) return; this.suggestions = suggestions .map((s, i, arr) => ({ title: getTitle(arr, i), value: getVal(arr, i), description: s.description })); this.completing = false; const l = Math.max(suggestions.length - 1, 0); this.moveSelect(Math.min(l, this.select)); cb && cb(); } reset() { this.input = ''; this.complete(() => { this.moveSelect(this.initial !== void 0 ? this.initial : 0); this.render(); }); this.render(); } exit() { if (this.clearFirst && this.input.length > 0) { this.reset(); } else { this.done = this.exited = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } } abort() { this.done = this.aborted = true; this.exited = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { this.done = true; this.aborted = this.exited = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } _(c, key) { let s1 = this.input.slice(0, this.cursor); let s2 = this.input.slice(this.cursor); this.input = `${s1}${c}${s2}`; this.cursor = s1.length+1; this.complete(this.render); this.render(); } delete() { if (this.cursor === 0) return this.bell(); let s1 = this.input.slice(0, this.cursor-1); let s2 = this.input.slice(this.cursor); this.input = `${s1}${s2}`; this.complete(this.render); this.cursor = this.cursor-1; this.render(); } deleteForward() { if(this.cursor*this.scale >= this.rendered.length) return this.bell(); let s1 = this.input.slice(0, this.cursor); let s2 = this.input.slice(this.cursor+1); this.input = `${s1}${s2}`; this.complete(this.render); this.render(); } first() { this.moveSelect(0); this.render(); } last() { this.moveSelect(this.suggestions.length - 1); this.render(); } up() { if (this.select === 0) { this.moveSelect(this.suggestions.length - 1); } else { this.moveSelect(this.select - 1); } this.render(); } down() { if (this.select === this.suggestions.length - 1) { this.moveSelect(0); } else { this.moveSelect(this.select + 1); } this.render(); } next() { if (this.select === this.suggestions.length - 1) { this.moveSelect(0); } else this.moveSelect(this.select + 1); this.render(); } nextPage() { this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1)); this.render(); } prevPage() { this.moveSelect(Math.max(this.select - this.limit, 0)); this.render(); } left() { if (this.cursor <= 0) return this.bell(); this.cursor = this.cursor-1; this.render(); } right() { if (this.cursor*this.scale >= this.rendered.length) return this.bell(); this.cursor = this.cursor+1; this.render(); } renderOption(v, hovered, isStart, isEnd) { let desc; let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : ' '; let title = hovered ? color.cyan().underline(v.title) : v.title; prefix = (hovered ? color.cyan(figures.pointer) + ' ' : ' ') + prefix; if (v.description) { desc = ` - ${v.description}`; if (prefix.length + title.length + desc.length >= this.out.columns || v.description.split(/\r?\n/).length > 1) { desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns }); } } return prefix + ' ' + title + color.gray(desc || ''); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); else this.out.write(clear(this.outputText, this.out.columns)); super.render(); let { startIndex, endIndex } = entriesToDisplay(this.select, this.choices.length, this.limit); this.outputText = [ style.symbol(this.done, this.aborted, this.exited), color.bold(this.msg), style.delimiter(this.completing), this.done && this.suggestions[this.select] ? this.suggestions[this.select].title : this.rendered = this.transform.render(this.input) ].join(' '); if (!this.done) { const suggestions = this.suggestions .slice(startIndex, endIndex) .map((item, i) => this.renderOption(item, this.select === i + startIndex, i === 0 && startIndex > 0, i + startIndex === endIndex - 1 && endIndex < this.choices.length)) .join('\n'); this.outputText += `\n` + (suggestions || color.gray(this.fallback.title)); } this.out.write(erase.line + cursor.to(0) + this.outputText); } } autocomplete = AutocompletePrompt; return autocomplete; } var autocompleteMultiselect; var hasRequiredAutocompleteMultiselect; function requireAutocompleteMultiselect () { if (hasRequiredAutocompleteMultiselect) return autocompleteMultiselect; hasRequiredAutocompleteMultiselect = 1; const color = requireKleur(); const { cursor } = requireSrc(); const MultiselectPrompt = requireMultiselect(); const { clear, style, figures } = requireUtil(); /** * MultiselectPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Array} opts.choices Array of choice objects * @param {String} [opts.hint] Hint to display * @param {String} [opts.warn] Hint shown for disabled choices * @param {Number} [opts.max] Max choices * @param {Number} [opts.cursor=0] Cursor start position * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to */ class AutocompleteMultiselectPrompt extends MultiselectPrompt { constructor(opts={}) { opts.overrideRender = true; super(opts); this.inputValue = ''; this.clear = clear('', this.out.columns); this.filteredOptions = this.value; this.render(); } last() { this.cursor = this.filteredOptions.length - 1; this.render(); } next() { this.cursor = (this.cursor + 1) % this.filteredOptions.length; this.render(); } up() { if (this.cursor === 0) { this.cursor = this.filteredOptions.length - 1; } else { this.cursor--; } this.render(); } down() { if (this.cursor === this.filteredOptions.length - 1) { this.cursor = 0; } else { this.cursor++; } this.render(); } left() { this.filteredOptions[this.cursor].selected = false; this.render(); } right() { if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell(); this.filteredOptions[this.cursor].selected = true; this.render(); } delete() { if (this.inputValue.length) { this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1); this.updateFilteredOptions(); } } updateFilteredOptions() { const currentHighlight = this.filteredOptions[this.cursor]; this.filteredOptions = this.value .filter(v => { if (this.inputValue) { if (typeof v.title === 'string') { if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) { return true; } } if (typeof v.value === 'string') { if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) { return true; } } return false; } return true; }); const newHighlightIndex = this.filteredOptions.findIndex(v => v === currentHighlight); this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex; this.render(); } handleSpaceToggle() { const v = this.filteredOptions[this.cursor]; if (v.selected) { v.selected = false; this.render(); } else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) { return this.bell(); } else { v.selected = true; this.render(); } } handleInputChange(c) { this.inputValue = this.inputValue + c; this.updateFilteredOptions(); } _(c, key) { if (c === ' ') { this.handleSpaceToggle(); } else { this.handleInputChange(c); } } renderInstructions() { if (this.instructions === undefined || this.instructions) { if (typeof this.instructions === 'string') { return this.instructions; } return ` Instructions: ${figures.arrowUp}/${figures.arrowDown}: Highlight option ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection [a,b,c]/delete: Filter choices enter/return: Complete answer `; } return ''; } renderCurrentInput() { return ` Filtered results for: ${this.inputValue ? this.inputValue : color.gray('Enter something to filter')}\n`; } renderOption(cursor, v, i) { let title; if (v.disabled) title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title); else title = cursor === i ? color.cyan().underline(v.title) : v.title; return (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + title } renderDoneOrInstructions() { if (this.done) { return this.value .filter(e => e.selected) .map(v => v.title) .join(', '); } const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()]; if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) { output.push(color.yellow(this.warn)); } return output.join(' '); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); super.render(); // print prompt let prompt = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.renderDoneOrInstructions() ].join(' '); if (this.showMinError) { prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`); this.showMinError = false; } prompt += this.renderOptions(this.filteredOptions); this.out.write(this.clear + prompt); this.clear = clear(prompt, this.out.columns); } } autocompleteMultiselect = AutocompleteMultiselectPrompt; return autocompleteMultiselect; } var confirm; var hasRequiredConfirm; function requireConfirm () { if (hasRequiredConfirm) return confirm; hasRequiredConfirm = 1; const color = requireKleur(); const Prompt = requirePrompt(); const { style, clear } = requireUtil(); const { erase, cursor } = requireSrc(); /** * ConfirmPrompt Base Element * @param {Object} opts Options * @param {String} opts.message Message * @param {Boolean} [opts.initial] Default value (true/false) * @param {Stream} [opts.stdin] The Readable stream to listen to * @param {Stream} [opts.stdout] The Writable stream to write readline data to * @param {String} [opts.yes] The "Yes" label * @param {String} [opts.yesOption] The "Yes" option when choosing between yes/no * @param {String} [opts.no] The "No" label * @param {String} [opts.noOption] The "No" option when choosing between yes/no */ class ConfirmPrompt extends Prompt { constructor(opts={}) { super(opts); this.msg = opts.message; this.value = opts.initial; this.initialValue = !!opts.initial; this.yesMsg = opts.yes || 'yes'; this.yesOption = opts.yesOption || '(Y/n)'; this.noMsg = opts.no || 'no'; this.noOption = opts.noOption || '(y/N)'; this.render(); } reset() { this.value = this.initialValue; this.fire(); this.render(); } exit() { this.abort(); } abort() { this.done = this.aborted = true; this.fire(); this.render(); this.out.write('\n'); this.close(); } submit() { this.value = this.value || false; this.done = true; this.aborted = false; this.fire(); this.render(); this.out.write('\n'); this.close(); } _(c, key) { if (c.toLowerCase() === 'y') { this.value = true; return this.submit(); } if (c.toLowerCase() === 'n') { this.value = false; return this.submit(); } return this.bell(); } render() { if (this.closed) return; if (this.firstRender) this.out.write(cursor.hide); else this.out.write(clear(this.outputText, this.out.columns)); super.render(); this.outputText = [ style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(this.done), this.done ? (this.value ? this.yesMsg : this.noMsg) : color.gray(this.initialValue ? this.yesOption : this.noOption) ].join(' '); this.out.write(erase.line + cursor.to(0) + this.outputText); } } confirm = ConfirmPrompt; return confirm; } var elements; var hasRequiredElements; function requireElements () { if (hasRequiredElements) return elements; hasRequiredElements = 1; elements = { TextPrompt: requireText(), SelectPrompt: requireSelect(), TogglePrompt: requireToggle(), DatePrompt: requireDate(), NumberPrompt: requireNumber(), MultiselectPrompt: requireMultiselect(), AutocompletePrompt: requireAutocomplete(), AutocompleteMultiselectPrompt: requireAutocompleteMultiselect(), ConfirmPrompt: requireConfirm() }; return elements; } var hasRequiredPrompts; function requirePrompts () { if (hasRequiredPrompts) return prompts$1; hasRequiredPrompts = 1; (function (exports) { const $ = exports; const el = requireElements(); const noop = v => v; function toPrompt(type, args, opts={}) { return new Promise((res, rej) => { const p = new el[type](args); const onAbort = opts.onAbort || noop; const onSubmit = opts.onSubmit || noop; const onExit = opts.onExit || noop; p.on('state', args.onState || noop); p.on('submit', x => res(onSubmit(x))); p.on('exit', x => res(onExit(x))); p.on('abort', x => rej(onAbort(x))); }); } /** * Text prompt * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {function} [args.onState] On state change callback * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.text = args => toPrompt('TextPrompt', args); /** * Password prompt with masked input * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {function} [args.onState] On state change callback * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.password = args => { args.style = 'password'; return $.text(args); }; /** * Prompt where input is invisible, like sudo * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {function} [args.onState] On state change callback * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.invisible = args => { args.style = 'invisible'; return $.text(args); }; /** * Number prompt * @param {string} args.message Prompt message to display * @param {number} args.initial Default number value * @param {function} [args.onState] On state change callback * @param {number} [args.max] Max value * @param {number} [args.min] Min value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {Boolean} [opts.float=false] Parse input as floats * @param {Number} [opts.round=2] Round floats to x decimals * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.number = args => toPrompt('NumberPrompt', args); /** * Date prompt * @param {string} args.message Prompt message to display * @param {number} args.initial Default number value * @param {function} [args.onState] On state change callback * @param {number} [args.max] Max value * @param {number} [args.min] Min value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {Boolean} [opts.float=false] Parse input as floats * @param {Number} [opts.round=2] Round floats to x decimals * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys * @param {function} [args.validate] Function to validate user input * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.date = args => toPrompt('DatePrompt', args); /** * Classic yes/no prompt * @param {string} args.message Prompt message to display * @param {boolean} [args.initial=false] Default value * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.confirm = args => toPrompt('ConfirmPrompt', args); /** * List prompt, split intput string by `seperator` * @param {string} args.message Prompt message to display * @param {string} [args.initial] Default string value * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {string} [args.separator] String separator * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input, in form of an `Array` */ $.list = args => { const sep = args.separator || ','; return toPrompt('TextPrompt', args, { onSubmit: str => str.split(sep).map(s => s.trim()) }); }; /** * Toggle/switch prompt * @param {string} args.message Prompt message to display * @param {boolean} [args.initial=false] Default value * @param {string} [args.active="on"] Text for `active` state * @param {string} [args.inactive="off"] Text for `inactive` state * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.toggle = args => toPrompt('TogglePrompt', args); /** * Interactive select prompt * @param {string} args.message Prompt message to display * @param {Array} args.choices Array of choices objects `[{ title, value }, ...]` * @param {number} [args.initial] Index of default value * @param {String} [args.hint] Hint to display * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.select = args => toPrompt('SelectPrompt', args); /** * Interactive multi-select / autocompleteMultiselect prompt * @param {string} args.message Prompt message to display * @param {Array} args.choices Array of choices objects `[{ title, value, [selected] }, ...]` * @param {number} [args.max] Max select * @param {string} [args.hint] Hint to display user * @param {Number} [args.cursor=0] Cursor start position * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.multiselect = args => { args.choices = [].concat(args.choices || []); const toSelected = items => items.filter(item => item.selected).map(item => item.value); return toPrompt('MultiselectPrompt', args, { onAbort: toSelected, onSubmit: toSelected }); }; $.autocompleteMultiselect = args => { args.choices = [].concat(args.choices || []); const toSelected = items => items.filter(item => item.selected).map(item => item.value); return toPrompt('AutocompleteMultiselectPrompt', args, { onAbort: toSelected, onSubmit: toSelected }); }; const byTitle = (input, choices) => Promise.resolve( choices.filter(item => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase()) ); /** * Interactive auto-complete prompt * @param {string} args.message Prompt message to display * @param {Array} args.choices Array of auto-complete choices objects `[{ title, value }, ...]` * @param {Function} [args.suggest] Function to filter results based on user input. Defaults to sort by `title` * @param {number} [args.limit=10] Max number of results to show * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible') * @param {String} [args.initial] Index of the default value * @param {boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input * @param {String} [args.fallback] Fallback message - defaults to initial value * @param {function} [args.onState] On state change callback * @param {Stream} [args.stdin] The Readable stream to listen to * @param {Stream} [args.stdout] The Writable stream to write readline data to * @returns {Promise} Promise with user input */ $.autocomplete = args => { args.suggest = args.suggest || byTitle; args.choices = [].concat(args.choices || []); return toPrompt('AutocompletePrompt', args); }; } (prompts$1)); return prompts$1; } var lib; var hasRequiredLib; function requireLib () { if (hasRequiredLib) return lib; hasRequiredLib = 1; const prompts = requirePrompts(); const passOn = ['suggest', 'format', 'onState', 'validate', 'onRender', 'type']; const noop = () => {}; /** * Prompt for a series of questions * @param {Array|Object} questions Single question object or Array of question objects * @param {Function} [onSubmit] Callback function called on prompt submit * @param {Function} [onCancel] Callback function called on cancel/abort * @returns {Object} Object with values from user input */ async function prompt(questions=[], { onSubmit=noop, onCancel=noop }={}) { const answers = {}; const override = prompt._override || {}; questions = [].concat(questions); let answer, question, quit, name, type, lastPrompt; const getFormattedAnswer = async (question, answer, skipValidation = false) => { if (!skipValidation && question.validate && question.validate(answer) !== true) { return; } return question.format ? await question.format(answer, answers) : answer }; for (question of questions) { ({ name, type } = question); // evaluate type first and skip if type is a falsy value if (typeof type === 'function') { type = await type(answer, { ...answers }, question); question['type'] = type; } if (!type) continue; // if property is a function, invoke it unless it's a special function for (let key in question) { if (passOn.includes(key)) continue; let value = question[key]; question[key] = typeof value === 'function' ? await value(answer, { ...answers }, lastPrompt) : value; } lastPrompt = question; if (typeof question.message !== 'string') { throw new Error('prompt message is required'); } // update vars in case they changed ({ name, type } = question); if (prompts[type] === void 0) { throw new Error(`prompt type (${type}) is not defined`); } if (override[question.name] !== undefined) { answer = await getFormattedAnswer(question, override[question.name]); if (answer !== undefined) { answers[name] = answer; continue; } } try { // Get the injected answer if there is one or prompt the user answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts[type](question); answers[name] = answer = await getFormattedAnswer(question, answer, true); quit = await onSubmit(question, answer, answers); } catch (err) { quit = !(await onCancel(question, answers)); } if (quit) return answers; } return answers; } function getInjectedAnswer(injected, deafultValue) { const answer = injected.shift(); if (answer instanceof Error) { throw answer; } return (answer === undefined) ? deafultValue : answer; } function inject(answers) { prompt._injected = (prompt._injected || []).concat(answers); } function override(answers) { prompt._override = Object.assign({}, answers); } lib = Object.assign(prompt, { prompt, prompts, inject, override }); return lib; } function isNodeLT(tar) { tar = (Array.isArray(tar) ? tar : tar.split('.')).map(Number); let i=0, src=process.versions.node.split('.').map(Number); for (; i < tar.length; i++) { if (src[i] > tar[i]) return false; if (tar[i] > src[i]) return true; } return false; } var prompts = isNodeLT('8.6.0') ? requireDist() : requireLib(); var prompt = /*@__PURE__*/getDefaultExportFromCjs(prompts); var index = /*#__PURE__*/_mergeNamespaces({ __proto__: null, default: prompt }, [prompts]); 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) => { var _a, _b; switch (true) { case key.sequence === "\x7F": if (this.currentKeyword && ((_a = this.currentKeyword) == null ? void 0 : _a.length) > 1) this.currentKeyword = (_b = this.currentKeyword) == null ? void 0 : _b.slice(0, -1); else this.currentKeyword = void 0; break; case ((key == null ? void 0 : key.ctrl) && (key == null ? void 0 : key.name) === "c"): case (key == null ? void 0 : key.name) === "escape": this.cancel(); onSubmit(void 0); break; case (key == null ? void 0 : key.name) === "enter": case (key == null ? void 0 : key.name) === "return": onSubmit(this.results[this.selectionIndex] || this.currentKeyword || ""); this.currentKeyword = void 0; break; case (key == null ? void 0 : key.name) === "up": if (this.selectionIndex && this.selectionIndex > 0) this.selectionIndex--; else this.selectionIndex = -1; break; case (key == null ? void 0 : 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 == null ? void 0 : key.ctrl) && !(key == null ? void 0 : 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(stripAnsi(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() { var _a; const cursortPos = this.keywordOffset() + (((_a = this.currentKeyword) == null ? void 0 : _a.length) || 0); this.write(`${ESC}${cursortPos}G`); } cancel() { this.write(`${ESC}J`); } 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"], ["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 == null ? void 0 : 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(); } 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(); const files = ctx.state.getFilepaths(); const cliFiles = ctx.config.standalone && !files.length ? await ctx.getTestFilepaths() : void 0; await ctx.changeNamePattern((filter == null ? void 0 : 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(); latestFilename = (filter == null ? void 0 : 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 == null ? void 0 : 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) { var _a, _b, _c; process.env.TEST = "true"; process.env.VITEST = "true"; (_a = process.env).NODE_ENV ?? (_a.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 ((_b = options.typecheck) == null ? void 0 : _b.only) === "boolean") (_c = options.typecheck).enabled ?? (_c.enabled = true); const ctx = await createVitest(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)) { process.exitCode = 1; return ctx; } } } const environmentPackage = getEnvPackageName(ctx.config.environment); if (environmentPackage && !await ctx.packageInstaller.ensureInstalled(environmentPackage, root)) { process.exitCode = 1; return ctx; } const stdin = (vitestOptions == null ? void 0 : vitestOptions.stdin) || process.stdin; const stdout = (vitestOptions == null ? void 0 : vitestOptions.stdout) || process.stdout; let stdinCleanup; if (stdin.isTTY && ctx.config.watch) stdinCleanup = registerConsoleShortcuts(ctx, stdin, stdout); ctx.onServerRestart((reason) => { ctx.report("onServerRestart", reason); if (process.env.VITEST_CLI_WRAPPER) process.exit(EXIT_CODE_RESTART); }); ctx.onAfterSetServer(() => { if (ctx.config.standalone) ctx.init(); else ctx.start(cliFilters); }); try { if (ctx.config.standalone) await ctx.init(); else await ctx.start(cliFilters); } catch (e) { process.exitCode = 1; await ctx.logger.printError(e, { fullStack: true, type: "Unhandled Error" }); ctx.logger.error("\n\n"); return ctx; } if (ctx.shouldKeepServer()) return ctx; stdinCleanup == null ? void 0 : stdinCleanup(); await ctx.close(); return ctx; } var cliApi = /*#__PURE__*/Object.freeze({ __proto__: null, startVitest: startVitest }); export { VitestPlugin as V, createMethodsRPC as a, VitestPackageInstaller as b, createVitest as c, cliApi as d, registerConsoleShortcuts as r, startVitest as s };