UNPKG

@elsikora/setup-wizard

Version:

Setup Wizard - CLI scaffolding utility

193 lines (190 loc) 9.21 kB
#!/usr/bin/env node import { EModule } from '../../domain/enum/module.enum.js'; import { EPackageJsonDependencyType } from '../../domain/enum/package-json-dependency-type.enum.js'; import { NodeCommandService } from '../../infrastructure/service/node-command.service.js'; import { COMMITLINT_CONFIG } from '../constant/commitlint/config.constant.js'; import { COMMITLINT_CONFIG_CORE_DEPENDENCIES } from '../constant/commitlint/core-dependencies.constant.js'; import { COMMITLINT_CONFIG_FILE_NAMES } from '../constant/commitlint/file-names.constant.js'; import { COMMITLINT_CONFIG_FILE_PATHS } from '../constant/commitlint/file-paths.constant.js'; import { COMMITLINT_CONFIG_HUSKY_COMMIT_MSG_SCRIPT } from '../constant/commitlint/husky-commit-msg-script.constant.js'; import { COMMITLINT_CONFIG_HUSKY } from '../constant/commitlint/husky-config.constant.js'; import { COMMITLINT_CONFIG_MESSAGES } from '../constant/commitlint/messages.constant.js'; import { COMMITLINT_CONFIG_SCRIPTS } from '../constant/commitlint/scripts.constant.js'; import { COMMITLINT_CONFIG_SUMMARY } from '../constant/commitlint/summary.constant.js'; import { PackageJsonService } from './package-json.service.js'; /** * Service for setting up and managing Commitlint and Commitizen configuration. * Provides functionality to enforce consistent commit message formats using Commitlint * and simplify commit creation using Commitizen. */ class CommitlintModuleService { /** CLI interface service for user interaction */ CLI_INTERFACE_SERVICE; /** Command service for executing shell commands */ COMMAND_SERVICE; /** Configuration service for managing app configuration */ CONFIG_SERVICE; /** File system service for file operations */ FILE_SYSTEM_SERVICE; /** Service for managing package.json */ PACKAGE_JSON_SERVICE; /** * Initializes a new instance of the CommitlintModuleService. * @param cliInterfaceService - Service for CLI user interactions * @param fileSystemService - Service for file system operations * @param configService - Service for managing app configuration */ constructor(cliInterfaceService, fileSystemService, configService) { this.CLI_INTERFACE_SERVICE = cliInterfaceService; this.FILE_SYSTEM_SERVICE = fileSystemService; this.COMMAND_SERVICE = new NodeCommandService(cliInterfaceService); this.PACKAGE_JSON_SERVICE = new PackageJsonService(fileSystemService, this.COMMAND_SERVICE); this.CONFIG_SERVICE = configService; } /** * Handles existing Commitlint/Commitizen setup. * Checks for existing configuration files and asks if user wants to remove them. * @returns Promise resolving to true if setup should proceed, false otherwise */ async handleExistingSetup() { const existingFiles = await this.findExistingConfigFiles(); if (existingFiles.length > 0) { const messageLines = [COMMITLINT_CONFIG_MESSAGES.existingFilesDetected]; messageLines.push(""); if (existingFiles.length > 0) { for (const file of existingFiles) { messageLines.push(`- ${file}`); } } messageLines.push("", COMMITLINT_CONFIG_MESSAGES.deleteFilesQuestion); const shouldDelete = await this.CLI_INTERFACE_SERVICE.confirm(messageLines.join("\n"), true); if (shouldDelete) { await Promise.all(existingFiles.map((file) => this.FILE_SYSTEM_SERVICE.deleteFile(file))); } else { this.CLI_INTERFACE_SERVICE.warn(COMMITLINT_CONFIG_MESSAGES.existingFilesAborted); return false; } } return true; } /** * Installs and configures Commitlint and Commitizen. * Sets up configuration files, git hooks, and package.json scripts. * @returns Promise resolving to the module setup result */ async install() { try { if (!(await this.shouldInstall())) { return { wasInstalled: false }; } if (!(await this.handleExistingSetup())) { return { wasInstalled: false }; } await this.setupCommitlint(); return { wasInstalled: true }; } catch (error) { this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.failedSetupError, error); throw error; } } /** * Determines if Commitlint/Commitizen should be installed. * Asks the user if they want to set up these tools for their project. * Uses the saved config value as default if it exists. * @returns Promise resolving to true if the module should be installed, false otherwise */ async shouldInstall() { try { return await this.CLI_INTERFACE_SERVICE.confirm(COMMITLINT_CONFIG_MESSAGES.confirmSetup, await this.CONFIG_SERVICE.isModuleEnabled(EModule.COMMITLINT)); } catch (error) { this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.failedConfirmation, error); return false; } } /** * Creates the Commitlint configuration file. */ async createConfigs() { await this.FILE_SYSTEM_SERVICE.writeFile(COMMITLINT_CONFIG_FILE_PATHS.configFile, COMMITLINT_CONFIG, "utf8"); } /** * Displays a summary of the setup results. */ displaySetupSummary() { const summary = [COMMITLINT_CONFIG_MESSAGES.configurationCreated, "", COMMITLINT_CONFIG_MESSAGES.generatedScriptsLabel, COMMITLINT_CONFIG_SUMMARY.commitDescription, "", COMMITLINT_CONFIG_MESSAGES.configurationFilesLabel, COMMITLINT_CONFIG_SUMMARY.configFileDescription, COMMITLINT_CONFIG_SUMMARY.huskyCommitMsgDescription, "", COMMITLINT_CONFIG_MESSAGES.huskyGitHooksInfo, COMMITLINT_CONFIG_MESSAGES.commitizenDescription]; this.CLI_INTERFACE_SERVICE.note(COMMITLINT_CONFIG_MESSAGES.setupCompleteTitle, summary.join("\n")); } /** * Finds existing Commitlint/Commitizen configuration files. * @returns Promise resolving to an array of file paths for existing configuration files */ async findExistingConfigFiles() { const existingFiles = []; for (const file of COMMITLINT_CONFIG_FILE_NAMES) { if (await this.FILE_SYSTEM_SERVICE.isPathExists(file)) { existingFiles.push(file); } } if (await this.FILE_SYSTEM_SERVICE.isPathExists(COMMITLINT_CONFIG_FILE_PATHS.huskyCommitMsgHook)) { existingFiles.push(COMMITLINT_CONFIG_FILE_PATHS.huskyCommitMsgHook); } return existingFiles; } /** * Sets up Commitlint and Commitizen. * Installs dependencies, creates configuration files, and configures git hooks. */ async setupCommitlint() { this.CLI_INTERFACE_SERVICE.startSpinner(COMMITLINT_CONFIG_MESSAGES.settingUpSpinner); try { await this.PACKAGE_JSON_SERVICE.installPackages(COMMITLINT_CONFIG_CORE_DEPENDENCIES, "latest", EPackageJsonDependencyType.DEV); await this.createConfigs(); await this.setupHusky(); await this.setupPackageJsonConfigs(); await this.setupScripts(); this.CLI_INTERFACE_SERVICE.stopSpinner(COMMITLINT_CONFIG_MESSAGES.configurationCompleted); this.displaySetupSummary(); } catch (error) { this.CLI_INTERFACE_SERVICE.stopSpinner(COMMITLINT_CONFIG_MESSAGES.failedSetupConfiguration); throw error; } } /** * Sets up Husky git hooks. * Initializes Husky, adds prepare script, and creates commit-msg and pre-push hooks. */ async setupHusky() { // Initialize husky await this.COMMAND_SERVICE.execute(COMMITLINT_CONFIG_HUSKY.initCommand); // Add prepare script if it doesn't exist await this.PACKAGE_JSON_SERVICE.addScript(COMMITLINT_CONFIG_SCRIPTS.prepare.name, COMMITLINT_CONFIG_SCRIPTS.prepare.command); await this.COMMAND_SERVICE.execute(COMMITLINT_CONFIG_HUSKY.mkdirCommand); // Create commit-msg hook await this.FILE_SYSTEM_SERVICE.writeFile(COMMITLINT_CONFIG_FILE_PATHS.huskyCommitMsgHook, COMMITLINT_CONFIG_HUSKY_COMMIT_MSG_SCRIPT, "utf8"); await this.COMMAND_SERVICE.execute(COMMITLINT_CONFIG_HUSKY.chmodCommand); } /** * Sets up Commitizen configuration in package.json. */ async setupPackageJsonConfigs() { const packageJson = await this.PACKAGE_JSON_SERVICE.get(); packageJson.config ??= {}; packageJson.config.commitizen = { path: COMMITLINT_CONFIG_MESSAGES.commitizenPath, }; await this.PACKAGE_JSON_SERVICE.set(packageJson); } /** * Sets up npm scripts for Commitizen. * Adds 'commit' script for starting the Commitizen CLI. */ async setupScripts() { await this.PACKAGE_JSON_SERVICE.addScript(COMMITLINT_CONFIG_SCRIPTS.commit.name, COMMITLINT_CONFIG_SCRIPTS.commit.command); } } export { CommitlintModuleService }; //# sourceMappingURL=commitlint-module.service.js.map