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.

762 lines (760 loc) 23.6 kB
import { __export, __reExport } from "./chunk-DuzeN18W.node.mjs"; import { ConsolaInstance, LogLevels } from "consola"; import { colorize, colors, getColor, stripAnsi } from "consola/utils"; import { Stats } from "node:fs"; import readdir from "tiny-readdir-glob"; import { minimatch } from "minimatch"; import chokidar from "chokidar"; import { exec } from "node:child_process"; import { createDefu, defu, defuArrayFn, defuFn } from "defu"; import { getRandomPort } from "get-port-please"; import { ChildProcess, ChildProcessWithoutNullStreams } from "child_process"; import { confirm, intro, isCancel, multiselect, outro, select, spinner, spinner as spinner$1, text } from "@clack/prompts"; //#region src/cleanup.d.ts /** * A function that performs cleanup operations. * Can be synchronous or asynchronous. */ type CleanupFunction = () => void | Promise<void>; /** * 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'); * }); * ``` */ declare function cleanupOnExit(cleanupFn: CleanupFunction): void; declare namespace filesystem_d_exports { export { calculateContentHash, calculateFileHash, copyFile, ensureDir, exists, existsSync, getStats, glob, matchPattern, readFile, removeDir, removeFile, watch, writeFile }; } import * as import_pathe from "pathe"; __reExport(filesystem_d_exports, import_pathe); // Export only the functions we use from globbing libraries /** * 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']); * ``` */ declare const glob: typeof readdir; /** * 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`); * }); * ``` */ declare const watch: typeof chokidar.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'); * } * ``` */ declare const matchPattern: typeof minimatch; // File system operations /** * 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'); * ``` */ declare function ensureDir(dirPath: string): Promise<void>; /** * 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!'); * ``` */ declare function writeFile(filePath: string, content: string): Promise<void>; /** * 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'); * ``` */ declare function readFile(filePath: string, encoding?: BufferEncoding): Promise<string>; /** * 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'); * } * ``` */ declare function existsSync(filePath: string): boolean; /** * 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'); * } * ``` */ declare function exists(filePath: string): Promise<boolean>; /** * 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()}`); * ``` */ declare function getStats(filePath: string): Promise<Stats>; /** * 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'); * ``` */ declare function copyFile(src: string, dest: string): Promise<void>; /** * 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'); * ``` */ declare function removeFile(filePath: string): Promise<void>; /** * 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'); * ``` */ declare function removeDir(dirPath: string): Promise<void>; /** * 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}`); * ``` */ declare function calculateFileHash(filePath: string): Promise<string>; /** * 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}`); * ``` */ declare function calculateContentHash(content: string): string; //#endregion //#region src/helpers.d.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); * } * ``` */ declare const execAsync: typeof exec.__promisify__; //#endregion //#region src/logger.d.ts /** * 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 }); * ``` */ declare const logger: ConsolaInstance; /** * Type alias for logger instances. */ type Logger = ConsolaInstance; // Convenience functions for common logging patterns /** Log informational messages */ declare const info: typeof logger.info; /** Log warning messages */ declare const warn: typeof logger.warn; /** Log error messages */ declare const error: typeof logger.error; /** Log debug messages (only shown when debug level is enabled) */ declare const debug: typeof logger.debug; /** Log success messages with green styling */ declare const success: typeof logger.success; /** Log failure messages with red styling */ declare const fail: typeof logger.fail; /** Log ready messages (typically for server/service startup) */ declare const ready: typeof logger.ready; /** Log start messages (typically for process/task initiation) */ declare const start: typeof logger.start; /** Log general messages */ declare const log: typeof logger.log; /** Display a message in a box for emphasis */ declare const box: typeof logger.box; /** * 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 * ``` */ declare function createLogger(tag: string): ConsolaInstance; /** * 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' } * ``` */ declare function logPerformance(operation: string, duration: number, data?: any): void; /** * 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 * }); * } * ``` */ declare function logWithContext(level: "info" | "warn" | "error" | "debug", context: string, message: string, data?: any): void; // Re-export color utilities for consistent styling across the package //#endregion //#region src/pact.d.ts /** * Regular expression for parsing Pact version strings. * Matches patterns like: 4.11.0, 4.11, 4.11.0-dev */ declare const PACT_VERSION_REGEX: RegExp; /** * 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'); * } * ``` */ declare function isAnyPactInstalled(match?: string): Promise<boolean>; /** * 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'); * } * ``` */ declare function getCurrentPactVersion(): Promise<string | undefined>; /** * 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); * ``` */ declare function installPact(version?: string, nightly?: boolean): Promise<{ stdout: string | Buffer; stderr: string | Buffer; }>; //#endregion //#region src/port.d.ts interface RandomPorts { public: number; service: number; onDemand: number; stratum: number; p2p: number; } /** * 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. */ declare function getRandomNetworkPorts(host?: string, startGap?: number, endGap?: number): Promise<RandomPorts>; /** * 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'); * } * ``` */ declare function isPortTaken(port: number | string): Promise<boolean>; //#endregion //#region src/process.d.ts /** * Options for running a binary/executable. */ interface RunBinOptions { /** Whether to suppress stdout output (default: false) */ silent?: boolean; /** Working directory for the process */ cwd?: string; /** Environment variables for the process */ env?: NodeJS.ProcessEnv; /** Whether to resolve the promise immediately when process starts (default: true) */ resolveOnStart?: boolean; /** Custom condition to resolve the promise based on stdout output */ resolveIf?: (data: string) => boolean; } /** * 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 * }); * ``` */ declare function runBin(bin: string, args: string[], options?: RunBinOptions): Promise<ChildProcessWithoutNullStreams>; /** * 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'); * ``` */ declare function killProcess(name: string): Promise<void>; /** * Information about a running process. */ interface ProcessInfo { /** Process ID */ pid: number; /** Command name or executable path */ command: string; /** Process status */ status: "running" | "stopped"; } /** * Options for spawning a simple process. */ interface SimpleProcessOptions { /** Working directory for the process */ cwd?: string; /** Environment variables for the process */ env?: NodeJS.ProcessEnv; /** How to handle stdio streams (default: 'pipe') */ stdio?: "pipe" | "inherit" | "ignore"; /** Whether to run the process detached from the parent (default: false) */ detached?: boolean; /** Timeout in milliseconds (not currently implemented) */ timeout?: number; } /** * 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}`); * }); * ``` */ declare function spawnProcess(command: string, args?: string[], options?: SimpleProcessOptions): ChildProcess; /** * 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'); * } * ``` */ declare function isProcessRunning(pid: number): boolean; /** * 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})`); * } * ``` */ declare function getProcessInfo(pid: number): Promise<ProcessInfo | null>; //#endregion //#region src/prompts.d.ts /** * Type for spinner instances created by @clack/prompts. */ type Spinner = ReturnType<typeof spinner$1>; /** * Re-exports from @clack/prompts for interactive CLI prompts. * * @example * ```typescript * import { select, text, multiselect, intro, outro } from '@pact-toolbox/node-utils'; * * intro('Welcome to the setup wizard!'); * * const name = await text({ * message: 'What is your project name?', * defaultValue: 'my-project' * }); * * const framework = await select({ * message: 'Pick a framework', * options: [ * { value: 'react', label: 'React' }, * { value: 'vue', label: 'Vue' }, * { value: 'svelte', label: 'Svelte' } * ] * }); * * const features = await multiselect({ * message: 'Select features', * options: [ * { value: 'typescript', label: 'TypeScript' }, * { value: 'eslint', label: 'ESLint' }, * { value: 'testing', label: 'Testing' } * ] * }); * * outro('Setup complete!'); * ``` */ //#endregion //#region src/ui.d.ts type ClackSpinner = ReturnType<typeof spinner$1>; // Spinner methods /** * 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!'); * ``` */ declare function startSpinner(text: string): ClackSpinner; /** * 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!'); * } * ``` */ declare function stopSpinner(success?: boolean, text?: string): void; /** * 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!'); * ``` */ declare function updateSpinner(text: string): void; // Box using consola utils /** * 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.' * ]); * ``` */ declare function boxMessage(title: string, content: string | string[]): void; // Simple table - since it's only used once, keep it minimal /** * 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'] * ] * ); * ``` */ declare function table(headers: string[], rows: string[][]): void; // Clear console /** * Clears the console screen. * * @example * ```typescript * clear(); * console.log('Fresh start!'); * ``` */ declare function clear(): void; declare namespace index_d_exports { export { LogLevels, Logger, PACT_VERSION_REGEX, ProcessInfo, RunBinOptions, SimpleProcessOptions, Spinner, box, boxMessage, calculateContentHash, calculateFileHash, cleanupOnExit, clear, colorize, colors, confirm, copyFile, createDefu, createLogger, debug, defu, defuArrayFn, defuFn, ensureDir, error, execAsync, exists, existsSync, fail, getColor, getCurrentPactVersion, getProcessInfo, getRandomNetworkPorts, getRandomPort, getStats, glob, info, installPact, intro, isAnyPactInstalled, isCancel, isPortTaken, isProcessRunning, killProcess, log, logPerformance, logWithContext, logger, matchPattern, multiselect, outro, readFile, ready, removeDir, removeFile, runBin, select, spawnProcess, spinner, start, startSpinner, stopSpinner, stripAnsi, success, table, text, updateSpinner, warn, watch, writeFile }; } __reExport(index_d_exports, filesystem_d_exports); //#endregion export { LogLevels, Logger, PACT_VERSION_REGEX, ProcessInfo, RunBinOptions, SimpleProcessOptions, Spinner, box, boxMessage, calculateContentHash, calculateFileHash, cleanupOnExit, clear, colorize, colors, confirm, copyFile, createDefu, createLogger, debug, defu, defuArrayFn, defuFn, ensureDir, error, execAsync, exists, existsSync, fail, getColor, getCurrentPactVersion, getProcessInfo, getRandomNetworkPorts, getRandomPort, getStats, glob, info, installPact, intro, isAnyPactInstalled, isCancel, isPortTaken, isProcessRunning, killProcess, log, logPerformance, logWithContext, logger, matchPattern, multiselect, outro, readFile, ready, removeDir, removeFile, runBin, select, spawnProcess, spinner, start, startSpinner, stopSpinner, stripAnsi, success, table, text, updateSpinner, warn, watch, writeFile }; //# sourceMappingURL=index.d.mts.map