@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
JavaScript
//#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