@decaf-ts/utils
Version:
module management utils for decaf-ts
164 lines • 6.33 kB
JavaScript
import { Encoding } from "./../utils/constants.js";
import { style } from "styled-string-builder";
import { Logging } from "@decaf-ts/logging";
/**
* @description A standard output writer for handling command execution output.
* @summary This class implements the OutputWriter interface and provides methods for
* handling various types of output from command execution, including standard output,
* error output, and exit codes. It also includes utility methods for parsing commands
* and resolving or rejecting promises based on execution results.
*
* @template R - The type of the resolved value, defaulting to string.
*
* @param cmd - The command string to be executed.
* @param lock - A PromiseExecutor to control the asynchronous flow.
* @param args - Additional arguments (unused in the current implementation).
*
* @class
* @example
* ```typescript
* import { StandardOutputWriter } from '@decaf-ts/utils';
* import { PromiseExecutor } from '@decaf-ts/utils';
*
* // Create a promise executor
* const executor: PromiseExecutor<string> = {
* resolve: (value) => console.log(`Resolved: ${value}`),
* reject: (error) => console.error(`Rejected: ${error.message}`)
* };
*
* // Create a standard output writer
* const writer = new StandardOutputWriter('ls -la', executor);
*
* // Use the writer to handle command output
* writer.data('File list output...');
* writer.exit(0, ['Command executed successfully']);
* ```
*
* @mermaid
* sequenceDiagram
* participant Client
* participant StandardOutputWriter
* participant Logger
* participant PromiseExecutor
*
* Client->>StandardOutputWriter: new StandardOutputWriter(cmd, lock)
* StandardOutputWriter->>Logger: Logging.for(cmd)
*
* Client->>StandardOutputWriter: data(chunk)
* StandardOutputWriter->>StandardOutputWriter: log("stdout", chunk)
* StandardOutputWriter->>Logger: logger.info(log)
*
* Client->>StandardOutputWriter: error(chunk)
* StandardOutputWriter->>StandardOutputWriter: log("stderr", chunk)
* StandardOutputWriter->>Logger: logger.info(log)
*
* Client->>StandardOutputWriter: exit(code, logs)
* StandardOutputWriter->>StandardOutputWriter: log("stdout", exitMessage)
* alt code === 0
* StandardOutputWriter->>StandardOutputWriter: resolve(logs)
* StandardOutputWriter->>PromiseExecutor: lock.resolve(reason)
* else code !== 0
* StandardOutputWriter->>StandardOutputWriter: reject(error)
* StandardOutputWriter->>PromiseExecutor: lock.reject(reason)
* end
*/
export class StandardOutputWriter {
constructor(cmd, lock,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
...args) {
this.cmd = cmd;
this.lock = lock;
this.logger = Logging.for(this.cmd);
}
/**
* @description Logs output to the console.
* @summary Formats and logs the given data with a timestamp and type indicator.
*
* @param type - The type of output (stdout or stderr).
* @param data - The data to be logged.
*/
log(type, data) {
data = Buffer.isBuffer(data) ? data.toString(Encoding) : data;
const log = type === "stderr" ? style(data).red.text : data;
this.logger.info(log);
}
/**
* @description Handles standard output data.
* @summary Logs the given chunk as standard output.
*
* @param chunk - The data chunk to be logged.
*/
data(chunk) {
this.log("stdout", String(chunk));
}
/**
* @description Handles error output data.
* @summary Logs the given chunk as error output.
*
* @param chunk - The error data chunk to be logged.
*/
error(chunk) {
this.log("stderr", String(chunk));
}
/**
* @description Handles error objects.
* @summary Logs the error message from the given Error object.
*
* @param err - The Error object to be logged.
*/
errors(err) {
this.log("stderr", `Error executing command exited : ${err}`);
}
/**
* @description Handles the exit of a command.
* @summary Logs the exit code and resolves or rejects the promise based on the code.
*
* @param code - The exit code of the command.
* @param logs - Array of log messages to be processed before exiting.
*/
exit(code, logs) {
this.log("stdout", `command exited code : ${code === 0 ? style(code.toString()).green.text : style(code === null ? "null" : code.toString()).red.text}`);
if (code === 0) {
this.resolve(logs.map((l) => l.trim()).join("\n"));
}
else {
this.reject(new Error(logs.length ? logs.join("\n") : code.toString()));
}
}
/**
* @description Parses a command string or array into components.
* @summary Converts the command into a consistent format and stores it, then returns it split into command and arguments.
*
* @param command - The command as a string or array of strings.
* @return A tuple containing the command and its arguments as separate elements.
*/
parseCommand(command) {
command = typeof command === "string" ? command.split(" ") : command;
this.cmd = command.join(" ");
return [command[0], command.slice(1)];
}
/**
* @description Resolves the promise with a success message.
* @summary Logs a success message and resolves the promise with the given reason.
*
* @param reason - The reason for resolving the promise.
*/
resolve(reason) {
this.log("stdout", `${this.cmd} executed successfully: ${style(reason ? "ran to completion" : reason).green}`);
this.lock.resolve(reason);
}
/**
* @description Rejects the promise with an error message.
* @summary Logs an error message and rejects the promise with the given reason.
*
* @param reason - The reason for rejecting the promise, either a number (exit code) or a string.
*/
reject(reason) {
if (!(reason instanceof Error)) {
reason = new Error(typeof reason === "number" ? `Exit code ${reason}` : reason);
}
this.log("stderr", `${this.cmd} failed to execute: ${style(reason.message).red}`);
this.lock.reject(reason);
}
}
//# sourceMappingURL=StandardOutputWriter.js.map