UNPKG

@pact-toolbox/node-utils

Version:

Essential Node.js utilities for building, testing, and managing applications in the Pact Toolbox ecosystem. This package provides a comprehensive set of utilities for file system operations, process management, logging, UI components, and more.

1,254 lines (1,243 loc) 34.5 kB
//#region rolldown:runtime var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion const consola = __toESM(require("consola")); const consola_utils = __toESM(require("consola/utils")); const node_fs_promises = __toESM(require("node:fs/promises")); const node_fs = __toESM(require("node:fs")); const pathe = __toESM(require("pathe")); const tiny_readdir_glob = __toESM(require("tiny-readdir-glob")); const minimatch = __toESM(require("minimatch")); const chokidar = __toESM(require("chokidar")); const node_crypto = __toESM(require("node:crypto")); const node_child_process = __toESM(require("node:child_process")); const node_util = __toESM(require("node:util")); const defu = __toESM(require("defu")); const get_port_please = __toESM(require("get-port-please")); const child_process = __toESM(require("child_process")); const __clack_prompts = __toESM(require("@clack/prompts")); //#region src/logger.ts /** * Determines the log level from environment variables. * Supports DEBUG and LOG_LEVEL environment variables. * * @returns The numeric log level (0-5) */ function getLogLevel() { if (process.env["DEBUG"] === "1" || process.env["DEBUG"] === "true") return 4; if (process.env["LOG_LEVEL"]) { const level = process.env["LOG_LEVEL"].toLowerCase(); switch (level) { case "silent": return 0; case "fatal": return 0; case "error": return 1; case "warn": return 2; case "log": return 3; case "info": return 3; case "debug": return 4; case "trace": return 5; default: return 3; } } return 3; } /** * Main logger instance configured with environment-based log level. * * Log levels: * - 0: silent/fatal * - 1: error * - 2: warn * - 3: info/log (default) * - 4: debug * - 5: trace * * Set log level via environment variables: * - DEBUG=1 or DEBUG=true for debug level * - LOG_LEVEL=debug/info/warn/error/silent * * @example * ```typescript * import { logger } from '@pact-toolbox/node-utils'; * * logger.info('Application started'); * logger.error('An error occurred', error); * logger.debug('Debug information', { data }); * ``` */ const logger = (0, consola.createConsola)({ level: getLogLevel(), formatOptions: { columns: 80, colors: true, compact: false, date: false } }); /** Log informational messages */ const info = logger.info.bind(logger); /** Log warning messages */ const warn = logger.warn.bind(logger); /** Log error messages */ const error = logger.error.bind(logger); /** Log debug messages (only shown when debug level is enabled) */ const debug = logger.debug.bind(logger); /** Log success messages with green styling */ const success = logger.success.bind(logger); /** Log failure messages with red styling */ const fail = logger.fail.bind(logger); /** Log ready messages (typically for server/service startup) */ const ready = logger.ready.bind(logger); /** Log start messages (typically for process/task initiation) */ const start = logger.start.bind(logger); /** Log general messages */ const log = logger.log.bind(logger); /** Display a message in a box for emphasis */ const box = logger.box.bind(logger); /** * Creates a tagged logger for a specific package or component. * Tagged loggers prefix all messages with the tag for easier identification. * * @param tag - The tag to prefix messages with * @returns A new logger instance with the specified tag * * @example * ```typescript * const networkLogger = createLogger('network'); * networkLogger.info('Connection established'); // [network] Connection established * * const dbLogger = createLogger('database'); * dbLogger.error('Query failed'); // [database] Query failed * ``` */ function createLogger(tag) { return logger.withTag(tag); } /** * Logs performance metrics for operations. * Only visible when debug level is enabled. * * @param operation - The name of the operation * @param duration - The duration in milliseconds * @param data - Optional additional data to log * * @example * ```typescript * const startTime = Date.now(); * await performOperation(); * const duration = Date.now() - startTime; * * logPerformance('database.query', duration, { query: 'SELECT * FROM users' }); * // [PERF] database.query completed in 123ms { query: 'SELECT * FROM users' } * ``` */ function logPerformance(operation, duration, data) { logger.debug(`[PERF] ${operation} completed in ${duration}ms`, data); } /** * Logs a message with explicit context/category and level. * Useful for dynamic logging where the level is determined at runtime. * * @param level - The log level to use * @param context - The context/category tag * @param message - The message to log * @param data - Optional additional data to log * * @example * ```typescript * function handleRequest(severity: string) { * const level = severity === 'critical' ? 'error' : 'warn'; * logWithContext(level, 'api', 'Request failed', { * endpoint: '/users', * status: 500 * }); * } * ``` */ function logWithContext(level, context, message, data) { const contextualLogger = logger.withTag(context); switch (level) { case "info": contextualLogger.info(message, data); break; case "warn": contextualLogger.warn(message, data); break; case "error": contextualLogger.error(message, data); break; case "debug": contextualLogger.debug(message, data); break; } } //#endregion //#region src/cleanup.ts var CleanupHandler = class { cleanupFunctions = /* @__PURE__ */ new Set(); cleanupRegistered = false; isCleaningUp = false; registerCleanupFunction(cleanupFn) { this.cleanupFunctions.add(cleanupFn); this.registerSignalHandlers(); } registerSignalHandlers() { if (this.cleanupRegistered) return; this.cleanupRegistered = true; const cleanup = async (signal) => { if (this.isCleaningUp) return; this.isCleaningUp = true; logger.info(`Received ${signal}, running cleanup functions...`); for (const cleanupFn of this.cleanupFunctions) try { await cleanupFn(); } catch (err) { logger.error("Error during cleanup:", err); } process.exit(signal === "uncaughtException" || signal === "unhandledRejection" ? 1 : 0); }; const signals = [ "SIGINT", "SIGTERM", "SIGQUIT", "SIGHUP", "exit", "uncaughtException", "unhandledRejection" ]; signals.forEach((signal) => { process.on(signal, async (reasonOrExitCode) => { if (signal === "exit") await cleanup(signal); else if (signal === "uncaughtException" || signal === "unhandledRejection") { logger.error(`${signal}:`, reasonOrExitCode); await cleanup(signal); } else await cleanup(signal); }); }); } }; const cleanupHandler = new CleanupHandler(); /** * Registers a cleanup function to be executed when the process exits. * * The cleanup function will be called on: * - SIGINT (Ctrl+C) * - SIGTERM (termination signal) * - SIGQUIT * - SIGHUP * - Normal process exit * - Uncaught exceptions * - Unhandled promise rejections * * Multiple cleanup functions can be registered and will be executed in the order * they were registered. If a cleanup function throws an error, it will be logged * but won't prevent other cleanup functions from running. * * @param cleanupFn - The cleanup function to register * * @example * ```typescript * import { cleanupOnExit } from '@pact-toolbox/node-utils'; * * const server = createServer(); * * cleanupOnExit(async () => { * await server.close(); * console.log('Server closed gracefully'); * }); * ``` */ function cleanupOnExit(cleanupFn) { cleanupHandler.registerCleanupFunction(cleanupFn); } //#endregion //#region src/filesystem.ts var filesystem_exports = {}; __export(filesystem_exports, { calculateContentHash: () => calculateContentHash, calculateFileHash: () => calculateFileHash, copyFile: () => copyFile, ensureDir: () => ensureDir, exists: () => exists, existsSync: () => existsSync, getStats: () => getStats, glob: () => glob, matchPattern: () => matchPattern, readFile: () => readFile, removeDir: () => removeDir, removeFile: () => removeFile, watch: () => watch, writeFile: () => writeFile }); __reExport(filesystem_exports, require("pathe")); /** * Reads directories recursively and returns files matching glob patterns. * Wrapper around tiny-readdir-glob for consistent API. * * @example * ```typescript * const files = await glob(['src', 'lib/*.js']); * ``` */ const glob = tiny_readdir_glob.default; /** * Watch files and directories for changes. * Wrapper around chokidar for file system watching. * * @example * ```typescript * const watcher = watch('src/', { * ignored: /node_modules/, * persistent: true * }); * * watcher.on('change', (path) => { * console.log(`File ${path} has been changed`); * }); * ``` */ const watch = chokidar.default.watch; /** * Test if a file path matches a glob pattern. * Wrapper around minimatch for pattern matching. * * @example * ```typescript * if (matchPattern('src/index.ts', '*.ts')) { * console.log('This is a TypeScript file'); * } * ``` */ const matchPattern = minimatch.minimatch; /** * Ensures a directory exists, creating it and any parent directories if necessary. * * @param dirPath - The path to the directory * @throws {Error} If directory creation fails * * @example * ```typescript * await ensureDir('/path/to/nested/directory'); * ``` */ async function ensureDir(dirPath) { if (!await (0, node_fs_promises.access)(dirPath).catch(() => false)) await (0, node_fs_promises.mkdir)(dirPath, { recursive: true }); } /** * Writes content to a file, creating parent directories if they don't exist. * Content is automatically trimmed before writing. * * @param filePath - The path to the file * @param content - The content to write * @throws {Error} If write operation fails * * @example * ```typescript * await writeFile('/path/to/file.txt', 'Hello, World!'); * ``` */ async function writeFile(filePath, content) { await ensureDir((0, pathe.dirname)(filePath)); await (0, node_fs_promises.writeFile)(filePath, content.trim()); } /** * Reads the content of a file as a string. * * @param filePath - The path to the file * @param encoding - The encoding to use (default: 'utf8') * @returns The file content as a string * @throws {Error} If file doesn't exist or read operation fails * * @example * ```typescript * const content = await readFile('/path/to/file.txt'); * ``` */ async function readFile(filePath, encoding = "utf8") { return (0, node_fs_promises.readFile)(filePath, encoding); } /** * Synchronously checks if a file or directory exists. * * @param filePath - The path to check * @returns true if the path exists, false otherwise * * @example * ```typescript * if (existsSync('/path/to/file')) { * console.log('File exists'); * } * ``` */ function existsSync(filePath) { return (0, node_fs.existsSync)(filePath); } /** * Asynchronously checks if a file or directory exists. * * @param filePath - The path to check * @returns Promise resolving to true if the path exists, false otherwise * * @example * ```typescript * if (await exists('/path/to/file')) { * console.log('File exists'); * } * ``` */ async function exists(filePath) { return (0, node_fs_promises.access)(filePath).then(() => true, () => false); } /** * Gets file or directory statistics. * * @param filePath - The path to the file or directory * @returns File statistics object * @throws {Error} If the path doesn't exist * * @example * ```typescript * const stats = await getStats('/path/to/file'); * console.log(`File size: ${stats.size} bytes`); * console.log(`Is directory: ${stats.isDirectory()}`); * ``` */ async function getStats(filePath) { return (0, node_fs_promises.stat)(filePath); } /** * Copies a file or directory from source to destination. * Creates parent directories of destination if they don't exist. * * @param src - The source path * @param dest - The destination path * @throws {Error} If copy operation fails * * @example * ```typescript * await copyFile('/path/to/source.txt', '/path/to/dest.txt'); * await copyFile('/path/to/source-dir', '/path/to/dest-dir'); * ``` */ async function copyFile(src, dest) { await ensureDir((0, pathe.dirname)(dest)); await (0, node_fs_promises.cp)(src, dest, { recursive: true }); } /** * Removes a file. Does not throw if the file doesn't exist. * * @param filePath - The path to the file to remove * * @example * ```typescript * await removeFile('/path/to/file.txt'); * ``` */ async function removeFile(filePath) { await (0, node_fs_promises.rm)(filePath, { force: true }); } /** * Removes a directory and all its contents. Does not throw if the directory doesn't exist. * * @param dirPath - The path to the directory to remove * * @example * ```typescript * await removeDir('/path/to/directory'); * ``` */ async function removeDir(dirPath) { await (0, node_fs_promises.rm)(dirPath, { recursive: true, force: true }); } /** * Calculates the SHA-256 hash of a file's contents. * * @param filePath - The path to the file * @returns The SHA-256 hash as a hex string, or empty string if file read fails * * @example * ```typescript * const hash = await calculateFileHash('/path/to/file.txt'); * console.log(`File hash: ${hash}`); * ``` */ async function calculateFileHash(filePath) { try { const content = await readFile(filePath); return (0, node_crypto.createHash)("sha256").update(content).digest("hex"); } catch { return ""; } } /** * Calculates the SHA-256 hash of a string content. * * @param content - The content to hash * @returns The SHA-256 hash as a hex string * * @example * ```typescript * const hash = calculateContentHash('Hello, World!'); * console.log(`Content hash: ${hash}`); * ``` */ function calculateContentHash(content) { return (0, node_crypto.createHash)("sha256").update(content, "utf8").digest("hex"); } //#endregion //#region src/helpers.ts /** * Promisified version of Node.js exec function for running shell commands. * * @param command - The command to execute * @returns Promise with stdout and stderr output * @throws {Error} If the command fails with non-zero exit code * * @example * ```typescript * import { execAsync } from '@pact-toolbox/node-utils'; * * try { * const { stdout, stderr } = await execAsync('ls -la'); * console.log('Output:', stdout); * } catch (error) { * console.error('Command failed:', error); * } * ``` */ const execAsync = (0, node_util.promisify)(node_child_process.exec); //#endregion //#region src/pact.ts /** * Regular expression for parsing Pact version strings. * Matches patterns like: 4.11.0, 4.11, 4.11.0-dev */ const PACT_VERSION_REGEX = /(\d+)\.(\d+)(?:\.(\d+))?(-[A-Za-z0-9]+)?/; /** * Checks if Pact is installed on the system. * * @param match - Optional string to match against the version (e.g., "4.11") * @returns true if Pact is installed (and optionally matches the version) * * @example * ```typescript * // Check if any Pact is installed * if (await isAnyPactInstalled()) { * console.log('Pact is installed'); * } * * // Check if Pact 4.11 is installed * if (await isAnyPactInstalled('4.11')) { * console.log('Pact 4.11 is installed'); * } * ``` */ async function isAnyPactInstalled(match) { const version = await getCurrentPactVersion(); return match ? version?.includes(match) ?? false : !!version; } /** * Gets the currently installed Pact version. * * @returns The version string (e.g., "4.11.0") or undefined if Pact is not installed * * @example * ```typescript * const version = await getCurrentPactVersion(); * if (version) { * console.log(`Pact version: ${version}`); * } else { * console.log('Pact is not installed'); * } * ``` */ async function getCurrentPactVersion() { try { const { stdout } = await execAsync("pact --version"); const match = stdout.match(PACT_VERSION_REGEX); if (match) return match[0]; return void 0; } catch { return void 0; } } /** * Installs Pact using pactup. * * @param version - Specific version to install (e.g., "4.11.0") * @param nightly - Whether to install the nightly build * @returns Command output with stdout and stderr * @throws {Error} If installation fails * * @example * ```typescript * // Install latest stable version * await installPact(); * * // Install specific version * await installPact('4.11.0'); * * // Install nightly build * await installPact(undefined, true); * ``` */ async function installPact(version, nightly) { if (nightly) return execAsync("npx pactup install --nightly"); if (version) return execAsync(`npx pactup install ${version}`); return execAsync("npx pactup install --latest"); } //#endregion //#region src/port.ts /** * Gets a series of random network ports with gaps between each. * * @param host - The host for which to get the ports. Defaults to '127.0.0.1'. * @param startGap - The minimum gap between successive ports. Defaults to 10. * @param endGap - The maximum gap between successive ports. Defaults to 100. * @returns An object containing the random ports assigned for public, service, on-demand, stratum, and p2p services. * @throws {Error} If it fails to find a suitable port for any of the services. */ async function getRandomNetworkPorts(host = "127.0.0.1", startGap = 10, endGap = 100) { if (startGap <= 0 || endGap <= 0 || startGap > endGap || endGap > 65535) throw new Error("Invalid port gap values provided."); try { const publicPort = await (0, get_port_please.getPort)({ host, random: true, name: "public" }); const service = await (0, get_port_please.getPort)({ port: publicPort + startGap, host, portRange: [publicPort + startGap, publicPort + endGap], name: "service" }); const onDemand = await (0, get_port_please.getPort)({ port: service + startGap, host, portRange: [service + startGap, service + endGap], name: "onDemand" }); const stratum = await (0, get_port_please.getPort)({ port: onDemand + startGap, host, portRange: [onDemand + startGap, onDemand + endGap], name: "stratum" }); const p2p = await (0, get_port_please.getPort)({ port: stratum + startGap, host, portRange: [stratum + startGap, stratum + endGap], name: "p2p" }); return { public: publicPort, service, onDemand, stratum, p2p }; } catch (error$1) { throw new Error(`Failed to get network ports: ${error$1.message}`); } } /** * Checks if a specific port is already in use. * * @param port - The port number to check * @returns true if the port is taken, false if available * * @example * ```typescript * if (await isPortTaken(3000)) { * console.log('Port 3000 is already in use'); * } else { * console.log('Port 3000 is available'); * } * ``` */ async function isPortTaken(port) { try { const availablePort = await (0, get_port_please.getPort)({ port: Number(port), host: "127.0.0.1" }); return availablePort !== Number(port); } catch { return true; } } //#endregion //#region src/process.ts /** * Runs a binary/executable with advanced control over process lifecycle. * Automatically registers cleanup handlers to ensure child processes are terminated on exit. * * @param bin - The binary/executable to run * @param args - Arguments to pass to the binary * @param options - Configuration options * @returns Promise resolving to the child process * * @example * ```typescript * // Run a simple command * const child = await runBin('node', ['--version']); * * // Run with custom resolution condition * const server = await runBin('node', ['server.js'], { * resolveIf: (output) => output.includes('Server started on port'), * silent: true * }); * ``` */ function runBin(bin, args, options = {}) { const { cwd = process.cwd(), silent = false, env = process.env, resolveOnStart = true, resolveIf } = options; return new Promise((resolve, reject) => { const child = (0, child_process.spawn)(bin, args, { cwd, env }); let resolved = false; const handleStdout = (data) => { const output = data.toString(); if (!silent) console.log(output); if (resolveIf && !resolved && resolveIf(output)) { resolved = true; resolve(child); } }; const handleStderr = (data) => { const errorOutput = data.toString(); logger.error(errorOutput); }; const handleError = (err) => { logger.error("Child process error:", err); if (!resolved) reject(err); }; const handleExit = (_code, _signal) => { if (!resolved) { resolved = true; resolve(child); } }; child.stdout.on("data", handleStdout); child.stderr.on("data", handleStderr); child.on("error", handleError); child.on("exit", handleExit); cleanupOnExit(() => { if (!child.killed) child.kill("SIGTERM"); }); if (resolveOnStart && !resolved) { resolved = true; resolve(child); } }); } /** * Kills all processes matching the given name. * Cross-platform implementation using taskkill on Windows and pkill on Unix-like systems. * * @param name - The process name to kill (without .exe extension on Windows) * * @example * ```typescript * await killProcess('node'); * await killProcess('my-server'); * ``` */ async function killProcess(name) { switch (process.platform) { case "win32": (0, child_process.exec)("taskkill /F /IM " + name + ".exe /T"); break; default: (0, child_process.exec)("pkill -f " + name); break; } } /** * Spawns a long-running process with simple monitoring. * Automatically registers cleanup handlers to ensure child processes are terminated on exit. * * @param command - The command to execute * @param args - Arguments to pass to the command * @param options - Configuration options * @returns The spawned child process * * @example * ```typescript * // Spawn a simple process * const child = spawnProcess('npm', ['run', 'dev']); * * // Spawn with custom options * const server = spawnProcess('node', ['server.js'], { * cwd: '/path/to/project', * env: { ...process.env, PORT: '3000' } * }); * * // Handle process output * child.stdout?.on('data', (data) => { * console.log(`Output: ${data}`); * }); * ``` */ function spawnProcess(command, args = [], options = {}) { const { cwd = process.cwd(), env = process.env, stdio = "pipe", detached = false } = options; const child = (0, child_process.spawn)(command, args, { cwd, env, stdio, detached, shell: true }); cleanupOnExit(() => { if (!child.killed) child.kill("SIGTERM"); }); return child; } /** * Checks if a process is running by PID. * Uses signal 0 to test process existence without actually sending a signal. * * @param pid - The process ID to check * @returns true if the process is running, false otherwise * * @example * ```typescript * if (isProcessRunning(12345)) { * console.log('Process 12345 is still running'); * } * ``` */ function isProcessRunning(pid) { try { process.kill(pid, 0); return true; } catch { return false; } } /** * Gets basic process information by PID. * Cross-platform implementation using tasklist on Windows and ps on Unix-like systems. * * @param pid - The process ID to get information for * @returns Process information or null if process not found * * @example * ```typescript * const info = await getProcessInfo(process.pid); * if (info) { * console.log(`Process ${info.pid}: ${info.command} (${info.status})`); * } * ``` */ async function getProcessInfo(pid) { if (!isProcessRunning(pid)) return null; try { const command = process.platform === "win32" ? `tasklist /fi "pid eq ${pid}" /fo csv /nh` : `ps -p ${pid} -o comm=`; const result = await execAsync(command); const output = typeof result === "string" ? result : result.stdout.toString(); const commandName = process.platform === "win32" ? output.split(",")[0]?.replace(/"/g, "") || "unknown" : output.trim(); return { pid, command: commandName, status: "running" }; } catch { return null; } } //#endregion //#region src/ui.ts let currentSpinner = null; /** * Starts a new spinner with the given text. * If a spinner is already running, it will be stopped first. * * @param text - The text to display with the spinner * @returns The spinner instance * * @example * ```typescript * const spinner = startSpinner('Loading...'); * // Do some work * stopSpinner(true, 'Done!'); * ``` */ function startSpinner(text$1) { if (currentSpinner) currentSpinner.stop(); currentSpinner = (0, __clack_prompts.spinner)(); currentSpinner.start(text$1); return currentSpinner; } /** * Stops the current spinner. * * @param success - Whether the operation was successful (affects log color) * @param text - Optional text to display when stopping * * @example * ```typescript * startSpinner('Processing...'); * try { * await doWork(); * stopSpinner(true, 'Processing complete!'); * } catch (error) { * stopSpinner(false, 'Processing failed!'); * } * ``` */ function stopSpinner(success$1 = true, text$1) { if (currentSpinner) { if (text$1) { currentSpinner.stop(text$1); if (success$1) __clack_prompts.log.success(text$1); else __clack_prompts.log.error(text$1); } else currentSpinner.stop(); currentSpinner = null; } } /** * Updates the text of the current spinner. * * @param text - The new text to display * * @example * ```typescript * startSpinner('Processing item 1 of 10...'); * for (let i = 1; i <= 10; i++) { * updateSpinner(`Processing item ${i} of 10...`); * await processItem(i); * } * stopSpinner(true, 'All items processed!'); * ``` */ function updateSpinner(text$1) { if (currentSpinner) currentSpinner.message(text$1); } /** * Displays a message in a bordered box for emphasis. * * @param title - The title to display in bold * @param content - The content lines (string or array of strings) * * @example * ```typescript * boxMessage('Important Notice', [ * 'Your configuration has been updated.', * 'Please restart the application.' * ]); * ``` */ function boxMessage(title, content) { const lines = Array.isArray(content) ? content : [content]; const boxContent = [ consola_utils.colors.bold(title), "", ...lines ].join("\n"); console.log((0, consola_utils.box)(boxContent)); } /** * Displays data in a simple table format. * Long cell values are truncated with ellipsis. * * @param headers - The table headers * @param rows - The table rows (2D array) * * @example * ```typescript * table( * ['Name', 'Status', 'Port'], * [ * ['Server 1', 'Running', '3000'], * ['Server 2', 'Stopped', '3001'], * ['Server 3', 'Running', '3002'] * ] * ); * ``` */ function table(headers, rows) { const columnWidths = headers.map((header, i) => { const maxWidth = Math.max(header.length, ...rows.map((row) => (row[i] || "").toString().length)); return Math.min(maxWidth, 40); }); const headerRow = headers.map((header, i) => header.padEnd(columnWidths[i] || 0)).join(" │ "); console.log(consola_utils.colors.bold(headerRow)); console.log("─".repeat(headerRow.length)); for (const row of rows) { const rowStr = row.map((cell, i) => { const str = (cell || "").toString(); return str.length > (columnWidths[i] || 0) ? str.substring(0, (columnWidths[i] || 0) - 3) + "..." : str.padEnd(columnWidths[i] || 0); }).join(" │ "); console.log(rowStr); } } /** * Clears the console screen. * * @example * ```typescript * clear(); * console.log('Fresh start!'); * ``` */ function clear() { console.clear(); } //#endregion //#region src/index.ts var src_exports = {}; __export(src_exports, { LogLevels: () => consola.LogLevels, PACT_VERSION_REGEX: () => PACT_VERSION_REGEX, box: () => box, boxMessage: () => boxMessage, calculateContentHash: () => calculateContentHash, calculateFileHash: () => calculateFileHash, cleanupOnExit: () => cleanupOnExit, clear: () => clear, colorize: () => consola_utils.colorize, colors: () => consola_utils.colors, confirm: () => __clack_prompts.confirm, copyFile: () => copyFile, createDefu: () => defu.createDefu, createLogger: () => createLogger, debug: () => debug, defu: () => defu.defu, defuArrayFn: () => defu.defuArrayFn, defuFn: () => defu.defuFn, ensureDir: () => ensureDir, error: () => error, execAsync: () => execAsync, exists: () => exists, existsSync: () => existsSync, fail: () => fail, getColor: () => consola_utils.getColor, getCurrentPactVersion: () => getCurrentPactVersion, getProcessInfo: () => getProcessInfo, getRandomNetworkPorts: () => getRandomNetworkPorts, getRandomPort: () => get_port_please.getRandomPort, getStats: () => getStats, glob: () => glob, info: () => info, installPact: () => installPact, intro: () => __clack_prompts.intro, isAnyPactInstalled: () => isAnyPactInstalled, isCancel: () => __clack_prompts.isCancel, isPortTaken: () => isPortTaken, isProcessRunning: () => isProcessRunning, killProcess: () => killProcess, log: () => log, logPerformance: () => logPerformance, logWithContext: () => logWithContext, logger: () => logger, matchPattern: () => matchPattern, multiselect: () => __clack_prompts.multiselect, outro: () => __clack_prompts.outro, readFile: () => readFile, ready: () => ready, removeDir: () => removeDir, removeFile: () => removeFile, runBin: () => runBin, select: () => __clack_prompts.select, spawnProcess: () => spawnProcess, spinner: () => __clack_prompts.spinner, start: () => start, startSpinner: () => startSpinner, stopSpinner: () => stopSpinner, stripAnsi: () => consola_utils.stripAnsi, success: () => success, table: () => table, text: () => __clack_prompts.text, updateSpinner: () => updateSpinner, warn: () => warn, watch: () => watch, writeFile: () => writeFile }); __reExport(src_exports, filesystem_exports); //#endregion Object.defineProperty(exports, 'LogLevels', { enumerable: true, get: function () { return consola.LogLevels; } }); exports.PACT_VERSION_REGEX = PACT_VERSION_REGEX; exports.box = box; exports.boxMessage = boxMessage; exports.calculateContentHash = calculateContentHash; exports.calculateFileHash = calculateFileHash; exports.cleanupOnExit = cleanupOnExit; exports.clear = clear; Object.defineProperty(exports, 'colorize', { enumerable: true, get: function () { return consola_utils.colorize; } }); Object.defineProperty(exports, 'colors', { enumerable: true, get: function () { return consola_utils.colors; } }); Object.defineProperty(exports, 'confirm', { enumerable: true, get: function () { return __clack_prompts.confirm; } }); exports.copyFile = copyFile; Object.defineProperty(exports, 'createDefu', { enumerable: true, get: function () { return defu.createDefu; } }); exports.createLogger = createLogger; exports.debug = debug; Object.defineProperty(exports, 'defu', { enumerable: true, get: function () { return defu.defu; } }); Object.defineProperty(exports, 'defuArrayFn', { enumerable: true, get: function () { return defu.defuArrayFn; } }); Object.defineProperty(exports, 'defuFn', { enumerable: true, get: function () { return defu.defuFn; } }); exports.ensureDir = ensureDir; exports.error = error; exports.execAsync = execAsync; exports.exists = exists; exports.existsSync = existsSync; exports.fail = fail; Object.defineProperty(exports, 'getColor', { enumerable: true, get: function () { return consola_utils.getColor; } }); exports.getCurrentPactVersion = getCurrentPactVersion; exports.getProcessInfo = getProcessInfo; exports.getRandomNetworkPorts = getRandomNetworkPorts; Object.defineProperty(exports, 'getRandomPort', { enumerable: true, get: function () { return get_port_please.getRandomPort; } }); exports.getStats = getStats; exports.glob = glob; exports.info = info; exports.installPact = installPact; Object.defineProperty(exports, 'intro', { enumerable: true, get: function () { return __clack_prompts.intro; } }); exports.isAnyPactInstalled = isAnyPactInstalled; Object.defineProperty(exports, 'isCancel', { enumerable: true, get: function () { return __clack_prompts.isCancel; } }); exports.isPortTaken = isPortTaken; exports.isProcessRunning = isProcessRunning; exports.killProcess = killProcess; exports.log = log; exports.logPerformance = logPerformance; exports.logWithContext = logWithContext; exports.logger = logger; exports.matchPattern = matchPattern; Object.defineProperty(exports, 'multiselect', { enumerable: true, get: function () { return __clack_prompts.multiselect; } }); Object.defineProperty(exports, 'outro', { enumerable: true, get: function () { return __clack_prompts.outro; } }); exports.readFile = readFile; exports.ready = ready; exports.removeDir = removeDir; exports.removeFile = removeFile; exports.runBin = runBin; Object.defineProperty(exports, 'select', { enumerable: true, get: function () { return __clack_prompts.select; } }); exports.spawnProcess = spawnProcess; Object.defineProperty(exports, 'spinner', { enumerable: true, get: function () { return __clack_prompts.spinner; } }); exports.start = start; exports.startSpinner = startSpinner; exports.stopSpinner = stopSpinner; Object.defineProperty(exports, 'stripAnsi', { enumerable: true, get: function () { return consola_utils.stripAnsi; } }); exports.success = success; exports.table = table; Object.defineProperty(exports, 'text', { enumerable: true, get: function () { return __clack_prompts.text; } }); exports.updateSpinner = updateSpinner; exports.warn = warn; exports.watch = watch; exports.writeFile = writeFile; //# sourceMappingURL=index.node.cjs.map