UNPKG

@faisalrmdhn08/allin-cli

Version:

A modern full-stack CLI tool based on Typescript designed to accelerate your app development process — setup your entire stack in one seamless command.

184 lines 9.4 kB
import { __getUserRealName, BASE_PATH, CACHE_BASE_PATH } from '../../config.js'; import { BACKEND_FRAMEWORKS, templatesMap } from '../../constants/global.js'; import { PathNotFoundError, UnidentifiedFrameworkError, UnidentifiedTemplateError, } from '../../exceptions/error.js'; import { __unableOverwriteProject } from '../../exceptions/trigger.js'; import { isUndefined } from '../../utils/guard.js'; import { infoBox, warnBox } from '../../utils/info-box.js'; import chalk from 'chalk'; import fse from 'fs-extra'; import inquirer from 'inquirer'; import path from 'path'; import { MicroGenerator } from './micro.js'; export class BackendGenerator { static #instance; microGenerator; constructor(microGenerator) { this.microGenerator = microGenerator; } static get instance() { if (!BackendGenerator.#instance) { BackendGenerator.#instance = new BackendGenerator(MicroGenerator.instance); } return BackendGenerator.#instance; } // -------------------------------------------------------------------------- // MAIN ENTRY // -------------------------------------------------------------------------- async generate(params) { if (params.isUsingCacheProject !== false && params.cachedEntries.length > 0) await this.__generateCachedProject(params); else await this.__generateNonCachedProject(params); } // -------------------------------------------------------------------------- // CACHED PROJECT GENERATION // -------------------------------------------------------------------------- async __generateCachedProject(params) { const cacheProjectChoices = params.cachedEntries.map((c) => c.name); const chosenProject = await inquirer.prompt({ name: 'selectedCachedProject', type: 'list', message: 'Choose a cached project to reuse', choices: cacheProjectChoices, }); const selectedEntry = params.cachedEntries.find((c) => c.name === chosenProject.selectedCachedProject); if (!selectedEntry) { throw new UnidentifiedTemplateError(`${chalk.bold('Unidentified template')}: ${chalk.bold(chosenProject.selectedCachedProject)} file template is not defined.`); } const desPath = path.join(params.projectDir, params.projectName); if (await fse.pathExists(desPath)) { await fse.remove(desPath); } await this.microGenerator.__loadCachedProject(CACHE_BASE_PATH, selectedEntry.name, params.projectType, desPath); } // -------------------------------------------------------------------------- // NON-CACHED PROJECT GENERATION // -------------------------------------------------------------------------- async __generateNonCachedProject(params) { const { backendFramework } = await inquirer.prompt([ { name: 'backendFramework', type: 'list', message: 'Which backend framework do you want to use:', choices: BACKEND_FRAMEWORKS.frameworks .sort((a, b) => a.name.localeCompare(b.name, 'en-US')) .map((f) => f.name), default: 'express', loop: false, when: () => isUndefined(params.optionValues.template), }, ]); const backendFrameworkResource = isUndefined(params.optionValues.template) ? BACKEND_FRAMEWORKS.frameworks.find((f) => f.name === backendFramework) : BACKEND_FRAMEWORKS.frameworks.find((f) => f.name === params.optionValues.template); if (!backendFrameworkResource) { throw new UnidentifiedFrameworkError(`${chalk.bold('Unidentified framework project')}: Backend framework resource is not defined.`); } const backendFrameworkTemplateFolder = params.templatesFiles.find((f) => f.name === backendFrameworkResource.templateName && f.isDirectory()); if (!backendFrameworkTemplateFolder) { throw new PathNotFoundError(`${chalk.bold('Path not found')}: Backend framework folder not found.`); } // DEFINE TEMPLATES PATHS const srcPath = path.join(backendFrameworkTemplateFolder.parentPath, backendFrameworkTemplateFolder.name); const destPath = path.join(params.projectDir, params.projectName ?? params.projectNameArg); __unableOverwriteProject(destPath, params.optionValues); const destPathExists = fse.existsSync(destPath); if (params.optionValues.force && !destPathExists) { warnBox('Warning Information', '-f, --force option will not be used because project does not exist.'); } // GET SELECTED FRAMEWORK const selectedFramework = isUndefined(params.optionValues.template) ? templatesMap(srcPath, destPath).get(backendFramework) : templatesMap(srcPath, destPath).get(params.optionValues.template); if (!selectedFramework) { const errorMsg = isUndefined(params.optionValues.template) ? `Unsupported framework: ${backendFramework}` : `Unsupported framework: ${params.optionValues.template}`; throw new Error(errorMsg); } // SETUP PROJECT BASE STRUCTURE const microGenerator = MicroGenerator.instance; const setupExecutor = await microGenerator.setupProject({ spinner: params.spinner, projectName: params.projectName ?? params.projectNameArg, projectType: params.projectType, selectedFramework: selectedFramework.actualName, sourcePath: selectedFramework.templateSource, desPath: selectedFramework.templateDest, optionValues: params.optionValues, }); const tempDir = path.join(BASE_PATH, 'templates/temp', params.projectName); // ------------------------------------------------------------------------ // OPTIONAL DOCKER SETUP // ------------------------------------------------------------------------ if (params.optionValues.docker) { const { addDocker, addDockerBake } = await inquirer.prompt([ { name: 'addDocker', type: 'confirm', message: 'Do you want us to add docker to your project? (optional)', default: false, }, { name: 'addDockerBake', type: 'confirm', message: 'Do you want us to add docker bake too? (optional)', default: false, when: (a) => a.addDocker !== false, }, ]); if (addDocker) { await microGenerator.setupDocker({ spinner: params.spinner, isAddingDocker: addDocker, isAddingBake: addDockerBake, selectedPackageManager: params.optionValues.packageManager, desPath: tempDir, }); } } // ------------------------------------------------------------------------ // DEPENDENCIES INSTALLATION // ------------------------------------------------------------------------ const dependencyPrompt = await inquirer.prompt([ { name: selectedFramework.promptKey, type: 'checkbox', message: 'Select dependencies to include in your project:', choices: selectedFramework.packages .sort((a, b) => a.name.localeCompare(b.name, 'en-US')) .map((p) => p.originName), loop: false, }, ]); const selectedDeps = dependencyPrompt[selectedFramework.promptKey]; if (selectedDeps.length < 1) { infoBox('Project Information', `To be honest, you can install the dependencies later, right ${chalk.bold((await __getUserRealName()).split(' ')[0])}?`); } await microGenerator.setupInstallation({ spinner: params.spinner, selectedDependencies: selectedDeps, selectedPackageManager: params.optionValues.packageManager, projectName: params.projectName ?? params.projectNameArg, desPath: tempDir, }); // ------------------------------------------------------------------------ // POST-SETUP CUSTOMIZATION // ------------------------------------------------------------------------ await microGenerator.setupOthers({ spinner: params.spinner, optionValues: params.optionValues, projectType: params.projectType, projectName: params.projectName ?? params.projectNameArg, selectedFramework: selectedFramework.name, desPath: tempDir, }); if (setupExecutor) await setupExecutor(); // ------------------------------------------------------------------------ // SUMMARY INFORMATION // ------------------------------------------------------------------------ infoBox('Project Information', `You can check the project at ${chalk.bold(selectedFramework.templateDest)}`); } } //# sourceMappingURL=backend.js.map