@decaf-ts/utils
Version:
module management utils for decaf-ts
136 lines • 5.24 kB
JavaScript
import { UserInput } from "./../input/input.js";
import { DefaultCommandOptions, DefaultCommandValues } from "./constants.js";
import { getDependencies, getPackageVersion } from "./../utils/fs.js";
import { printBanner } from "./../output/common.js";
import { LoggedClass, LoggedEnvironment, Logging, } from "@decaf-ts/logging";
/**
* @class Command
* @abstract
* @template I - The type of input options for the command.
* @template R - The return type of the command execution.
* @memberOf module:utils
* @description Abstract base class for command implementation.
* @summary Provides a structure for creating command-line interface commands with input handling, logging, and execution flow.
*
* @param {string} name - The name of the command.
* @param {CommandOptions<I>} [inputs] - The input options for the command.
* @param {string[]} [requirements] - The list of required dependencies for the command.
*/
export class Command extends LoggedClass {
constructor(name, inputs = {}, requirements = []) {
super();
this.name = name;
this.inputs = inputs;
this.requirements = requirements;
if (!Command.log) {
Object.defineProperty(Command, "log", {
writable: false,
value: Logging.for(Command.name),
});
}
this.inputs = Object.assign({}, DefaultCommandOptions, inputs);
}
/**
* @protected
* @async
* @description Checks if all required dependencies are present.
* @summary Retrieves the list of dependencies and compares it against the required dependencies for the command.
* @returns {Promise<void>} A promise that resolves when the check is complete.
*
* @mermaid
* sequenceDiagram
* participant Command
* participant getDependencies
* participant Set
* Command->>getDependencies: Call
* getDependencies-->>Command: Return {prod, dev, peer}
* Command->>Set: Create Set from prod, dev, peer
* Set-->>Command: Return unique dependencies
* Command->>Command: Compare against requirements
* alt Missing dependencies
* Command->>Command: Add to missing list
* end
* Note over Command: If missing.length > 0, handle missing dependencies
*/
async checkRequirements() {
const { prod, dev, peer } = await getDependencies();
const missing = [];
const fullList = Array.from(new Set([...prod, ...dev, ...peer]).values()).map((d) => d.name);
for (const dep of this.requirements)
if (!fullList.includes(dep))
missing.push(dep);
if (!missing.length)
return;
}
/**
* @protected
* @description Provides help information for the command.
* @summary This method should be overridden in derived classes to provide specific help information.
* @param {ParseArgsResult} args - The parsed command-line arguments.
* @returns {void}
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
help(args) {
return this.log.info(`This is help. I'm no use because I should have been overridden.`);
}
/**
* @async
* @description Executes the command.
* @summary This method handles the overall execution flow of the command, including parsing arguments,
* setting up logging, checking for version or help requests, and running the command.
* @returns {Promise<R | string | void>} A promise that resolves with the command's result.
*
* @mermaid
* sequenceDiagram
* participant Command
* participant UserInput
* participant Logging
* participant getPackageVersion
* participant printBanner
* Command->>UserInput: parseArgs(inputs)
* UserInput-->>Command: Return ParseArgsResult
* Command->>Command: Process options
* Command->>Logging: setConfig(options)
* alt version requested
* Command->>getPackageVersion: Call
* getPackageVersion-->>Command: Return version
* else help requested
* Command->>Command: help(args)
* else banner requested
* Command->>printBanner: Call
* end
* Command->>Command: run(args)
* alt error occurs
* Command->>Command: Log error
* end
* Command-->>Command: Return result
*/
async execute() {
const args = UserInput.parseArgs(this.inputs);
const env = LoggedEnvironment.accumulate(DefaultCommandValues).accumulate(args.values);
const { version, help, banner } = env;
if (version) {
return getPackageVersion();
}
if (help) {
return this.help(args);
}
if (banner)
printBanner(this.log.for(printBanner, {
timestamp: false,
style: false,
context: false,
logLevel: false,
}));
let result;
// eslint-disable-next-line no-useless-catch
try {
result = await this.run(env);
}
catch (e) {
throw e;
}
return result;
}
}
//# sourceMappingURL=command.js.map