@modyo/cli
Version:
Modyo Command Line Interface
222 lines (214 loc) • 7.25 kB
JavaScript
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)}`))
})