@megaorm/cli
Version:
This package allows you to communicate with MegaORM via commands directly from the command line interface (CLI).
170 lines • 7.85 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommandHandler = exports.CommandHandlerError = void 0;
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = require("path");
const test_1 = require("@megaorm/test");
/**
* Custom error class for handling errors related to command operations.
*/
class CommandHandlerError extends Error {
}
exports.CommandHandlerError = CommandHandlerError;
/**
* Checks if the provided name matches the pattern for a valid command file.
*
* @param name The name to check if it matches a command file pattern.
* @returns `true` if the name matches the command file pattern (e.g., `Fetch.js`), otherwise `false`.
*/
function isFile(name) {
// Pattern example: Fetch.js
return /^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)*\.(ts|js)$/.test(name);
}
/**
* Checks if the provided name matches the pattern for a valid TypeScript output file (either a map or declaration file).
*
* @param name - The name to check if it matches a TypeScript output file pattern.
* @returns `true` if the name matches the pattern for a `.js.map` or `.d.ts` file, otherwise `false`.
*/
function isMappedFile(name) {
// Pattern example: Fetch.js.map or Fetch.d.ts
return /^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)*(\.js\.map|\.d\.ts)$/.test(name);
}
/**
* Safely deletes multiple command files at the specified paths.
*
* This function calls `unlink` for each path provided in the array, attempting to
* remove each corresponding file.
*
* @param paths An array of strings representing the absolute paths of the command files to be deleted.
* @returns A promise that resolves when all files are removed.
*/
function unlink(paths) {
return new Promise((resolve, reject) => {
return Promise.all(paths.map((path) => promises_1.default.unlink(path)))
.then(resolve)
.catch(reject);
});
}
/**
* This class provides functionality for adding, and removing command files
*
*/
class CommandHandler {
/**
* Instantiates a new CommandHandler.
*/
constructor() {
this.assets = (0, path_1.resolve)(__dirname, '../../assets');
}
/**
* Collects the absolute paths of command files from the specified directory.
*
* @param path The directory path from which to collect command files.
* @param map A boolean indicating whether to include mapped files (e.g., `.js.map`) in the resulting paths.
* @returns A promise that resolves with an array of absolute paths to valid command files.
* @throws `CommandHandlerError` if there is an issue collecting the files or if an invalid command file is encountered.
*/
collectPaths(path, map) {
return new Promise((resolve, reject) => {
promises_1.default.readdir(path)
.then((result) => {
// check if the directory is empty
if ((0, test_1.isEmptyArr)(result))
return resolve(result);
// filter map files
const files = map
? result
: result.filter((name) => !isMappedFile(name));
// validate each file
for (const file of files) {
if (!isFile(file)) {
if (map && isMappedFile(file))
continue;
return reject(new CommandHandlerError(`Invalid command file: ${String(file)}`));
}
}
return resolve(files.map((file) => (0, path_1.resolve)(path, file)));
})
.catch((e) => reject(new CommandHandlerError(e.message)));
});
}
/**
* Creates a new command file in the specified path.
*
* This method creates a new file for the specified command name in the given directory path.
* You can choose to create a TypeScript file or a JavaScript file based on the provided boolean flag.
*
* @param name The PascalCase command name.
* @param path The directory path where the command file will be created.
* @param ts A boolean indicating whether to create a TypeScript file (`true`) or a JavaScript file (`false`).
* @returns A promise that resolves with a success message indicating the path of the created command file.
* @throws `CommandHandlerError` if the command name is invalid, the path is empty, or if any errors occur during file operations.
* @note The command name must be in PascalCase, e.g., FetchCommand, RollbackCommand.
*/
add(name, path, ts) {
return new Promise((resolve, reject) => {
if (!(0, test_1.isPascalCase)(name)) {
return reject(new CommandHandlerError(`Invalid command name: ${String(name)}`));
}
if (!(0, test_1.isFullStr)(path)) {
return reject(new CommandHandlerError(`Invalid path: ${String(path)}`));
}
if (!(0, test_1.isBool)(ts))
ts = false;
const ext = ts ? 'ts' : 'js';
const layout = ts ? 'ts/command.txt' : 'js/command.txt';
const content = (0, path_1.resolve)(this.assets, layout);
promises_1.default.readFile(content, 'utf-8')
.then((template) => {
const className = name;
const fileName = className.concat('.', ext);
const filePath = (0, path_1.resolve)(path, fileName);
const fileContent = template
.replace(/\[className\]/g, className)
.replace(/\[fileName\]/g, fileName);
// Create command file
promises_1.default.writeFile(filePath, fileContent, 'utf-8')
.then(() => resolve(`Command added in: ${filePath}`))
.catch((e) => reject(new CommandHandlerError(e.message)));
})
.catch((e) => reject(new CommandHandlerError(e.message)));
});
}
/**
* Removes the command file in the specified path.
*
* @param name The PascalCase command name to be removed.
* @param path The directory path where the command files are located.
* @returns A promise that resolves with a success message indicating how many command files were removed.
* @throws `CommandHandlerError` if the command name is invalid, the path is empty.
* @note The command name must be in PascalCase, e.g., FetchCommand, RollbackCommand.
*/
remove(name, path) {
return new Promise((resolve, reject) => {
if (!(0, test_1.isPascalCase)(name)) {
return reject(new CommandHandlerError(`Invalid command name: ${String(name)}`));
}
if (!(0, test_1.isFullStr)(path)) {
return reject(new CommandHandlerError(`Invalid path: ${String(path)}`));
}
return this.collectPaths(path, true)
.then((paths) => {
const unlinkPaths = paths.filter((path) => new RegExp(`${name}\.(ts|js|js\.map|d\.ts)$`).test(path));
if (unlinkPaths.length === 0) {
return Promise.reject(new CommandHandlerError(`No command file found for: ${name}`));
}
const message = `${unlinkPaths.length} command file${unlinkPaths.length === 1 ? '' : 's'} removed in:\n${unlinkPaths.join('\n')}`;
return unlink(unlinkPaths)
.then(() => resolve(message))
.catch(reject);
})
.catch(reject);
});
}
}
exports.CommandHandler = CommandHandler;
//# sourceMappingURL=CommandHandler.js.map