@settlemint/sdk-utils
Version:
Shared utilities and helper functions for SettleMint SDK modules
1 lines • 20.6 kB
Source Map (JSON)
{"version":3,"file":"terminal.cjs","names":["output: string","msg: string","message: string","code: number","output: string[]","command: string","args: string[]","options?: ExecuteCommandOptions","data: Buffer | string","msg: string","message: string","level: \"info\" | \"warn\"","title: string","items: Array<string | string[]>","items","msg: string","message: string","originalError: Error","options: SpinnerOptions<R>","error: Error","isInCi","spinner","val: string","s: string","value: string","maxLength: number","title: string","data: unknown[]","table","Table"],"sources":["../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts"],"sourcesContent":["/**\n * Returns true if the terminal should print, false otherwise.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n return process.env.SETTLEMINT_DISABLE_TERMINAL !== \"true\";\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\n};\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning level formatting.\n * Regular notes are displayed in normal text, while warnings are shown in yellow.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param message - The message to display as a note\n * @param level - The note level: \"info\" (default) or \"warn\" for warning styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n */\nexport const note = (message: string, level: \"info\" | \"warn\" = \"info\"): void => {\n if (!shouldPrint()) {\n return;\n }\n const maskedMessage = maskTokens(message);\n\n console.log(\"\");\n if (level === \"warn\") {\n console.warn(yellowBright(maskedMessage));\n return;\n }\n\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n const errorMessage = maskTokens(error.message);\n note(redBright(`${errorMessage}\\n\\n${error.stack}`));\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\n};\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n"],"mappings":"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"}