UNPKG

@modyo/cli

Version:

Modyo Command Line Interface

222 lines (214 loc) 7.25 kB
const fs = require('fs-extra') const _ = require('lodash') const chalk = require('chalk') const path = require('path') const inquirer = require('inquirer') const mustache = require('mustache') const rimraf = require('rimraf') const { resolveWidgetPath, getAuthToken, ensureFoldersAndFiles, installDependencies, printFinishedMessage, selectSite, addWidgetToConfig, resolveWidgetSrcPath } = require('../../helpers') /* * Return a list of questions to configure the project */ const generateProjectQuestions = (options, to, continueInquiring) => [ { type: 'confirm', when: (!options.force && fs.existsSync(to)), message: 'Target directory exists. Overwrite?', default: false, name: 'replaceDir' }, { type: 'list', name: 'packageManager', when: (options.packageManager !== 'npm' && options.packageManager !== 'yarn') && continueInquiring, default: 'yarn', message: 'Should we run `npm install` for you after the project has been created? (recommended)', choices: [ { name: 'Yes, use NPM', value: 'npm', short: 'npm' }, { name: 'No, use Yarn', value: 'yarn', short: 'yarn' } ] }, { type: 'input', name: 'accountUrl', when: (!options.accountUrl && continueInquiring), message: 'Please insert your account url', default: 'https://dynamicbank.modyo.cloud', validate(value) { const pass = value.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%.+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%+.~#?&//=]*)/i) if (pass) { return true } return 'Please enter a valid HTTP/HTTPS url' } } ] /* * Return the paths of the templates files to be apply with mustache */ const resolveProjectPathNames = ((projectName, projectPath) => { const templatePaths = { package_json: path.resolve(projectPath, 'package.json'), readme: path.resolve(projectPath, 'README.md'), license: path.resolve(projectPath, 'LICENSE.md'), modyorc: path.resolve(projectPath, '.modyorc') } return { templatePaths } }) /* * Apply mustache to templates of the project created */ const renderWidgetProjectModyoRC = (name, templateFiles, answers) => { const templateData = { projectName: name, widgetKey: _.snakeCase(name), accountUrl: answers.accountUrl, packageManager: answers.packageManager, selectedSite: answers.selectedSite, modyoVersion: answers.modyoVersion, year: new Date().getFullYear() } Object.keys(templateFiles).forEach((keyname) => { const template = fs.readFileSync(templateFiles[keyname], 'utf-8') const templateRendered = mustache.render(template, templateData) fs.writeFileSync(templateFiles[keyname], templateRendered, 'utf-8') }) } /* * Generate project configuration input */ const generateConfigWidget = (name, targetDirectory, options) => { const continueInquiring = (response) => ( !fs.existsSync(targetDirectory) || options.force || (fs.existsSync(targetDirectory) && response.replaceDir) ) return inquirer.prompt(generateProjectQuestions(options, targetDirectory, continueInquiring)) .then((answers) => { const optionsPatched = Object.assign(options, answers) if (!continueInquiring(answers)) throw (new Error('Process canceled')) return getAuthToken(optionsPatched) .then((token) => selectSite(optionsPatched, token).then((site) => { optionsPatched.selectedSite = site optionsPatched.userToken = token if (optionsPatched.replaceDir || optionsPatched.force) rimraf.sync(targetDirectory) return optionsPatched }) .catch((err) => { throw (err) })) .catch((err) => { throw (err) }) }) .catch((err) => { throw (err) }) } /* * Core logic to create a new widget */ const createNewWidgetProject = (name, widgetDir, answers, install, logger) => { logger.info(`Creating a new ${chalk.green('Modyo™')} Widget Project ${chalk.cyan(name)} in ${chalk.yellow(widgetDir)}.`) const paths = resolveProjectPathNames(name, widgetDir) ensureFoldersAndFiles('widget', widgetDir) renderWidgetProjectModyoRC(name, paths.templatePaths, answers) if (install) { return installDependencies(widgetDir, answers.packageManager, logger) .then(() => { printFinishedMessage(widgetDir, logger, install, answers.packageManager) return Promise.resolve({ widgetDir, answers }) }) .catch((err) => { throw err }) } printFinishedMessage(widgetDir, logger, true, answers.packageManager) return Promise.resolve({ widgetDir, answers }) } /* * Apply mustache to templates of the widget created */ const renderWidgetTemplates = (widgetKey, name, templateFiles) => { const templateData = { widget_name: name, widget_key: widgetKey, widget_title: name, componentName: _.upperFirst(_.camelCase(widgetKey)), widget_description: `Modyo ${name}`, main_js: 'main.js' } Object.keys(templateFiles).forEach((keyname) => { const template = fs.readFileSync(templateFiles[keyname], 'utf8') const templateRendered = mustache.render(template, templateData) fs.writeFile(templateFiles[keyname], templateRendered, 'utf8') }) } /* * Return the paths of the templates files to be apply with mustache */ const resolveWidgetPathnames = ((widgetName, widgetPath) => { const templatePaths = { main_js: path.resolve(widgetPath, 'main.js'), app_vue: path.resolve(widgetPath, 'App.vue'), store_js: path.resolve(widgetPath, 'store.js') } return { templatePaths } }) /* * Core logic to create a new widget */ const addNewWidget = (name, targetDirectory, options, logger) => { const key = _.snakeCase(name) const paths = resolveWidgetPathnames(key, targetDirectory) ensureFoldersAndFiles(options.app_type, targetDirectory) renderWidgetTemplates(key, name, paths.templatePaths) return addWidgetToConfig(key, name, targetDirectory) .then(() => { const message = `${name} created successfully` logger.info(`${chalk.green(message)}`) }) .catch((err) => { logger.info(`ERROR: ${chalk.red(err)}`); throw err }) } /* * Add Widget */ const autoaddWidget = ((widgetName, options, logger) => { const targetDirectory = resolveWidgetSrcPath(widgetName) const answers = {} if (!options.app_type) { answers.app_type = 'blank_vue_widget' } const optionsPatched = Object.assign(options, answers) return addNewWidget(widgetName, targetDirectory, optionsPatched, logger) .catch((err) => { logger.warn(`ERROR: ${chalk.red(err)}`); throw err }) }) /* * Create project */ module.exports = ((widgetName, options, logger) => { const targetDirectory = resolveWidgetPath(widgetName) generateConfigWidget(widgetName, targetDirectory, options) .then((answers) => createNewWidgetProject( widgetName, targetDirectory, answers, !options.noInstall, logger )) .then(() => { const optionsForForceWidgetCreation = Object.assign(options, { force: true }) return autoaddWidget(widgetName, optionsForForceWidgetCreation, logger) }) .catch((err) => { throw err }) .catch((err) => logger.info(`ERROR: ${chalk.red(err)}`)) })