roc
Version:
Build modern web applications easily
357 lines (292 loc) • 12.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = init;
var _fsExtra = require('fs-extra');
var _fsExtra2 = _interopRequireDefault(_fsExtra);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _crossSpawn = require('cross-spawn');
var _inquirer = require('inquirer');
var _inquirer2 = _interopRequireDefault(_inquirer);
var _replace = require('replace');
var _replace2 = _interopRequireDefault(_replace);
var _chalk = require('chalk');
var _chalk2 = _interopRequireDefault(_chalk);
var _github = require('./helpers/github');
var _general = require('./helpers/general');
var _style = require('../helpers/style');
var _helpers = require('../helpers');
var _unzip = require('./helpers/unzip');
var _unzip2 = _interopRequireDefault(_unzip);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* This should be fetched from a server!
*/
const templates = [{
name: 'Simple Roc App',
description: 'A simple start on a generic web application',
identifier: 'web-app',
repo: 'rocjs/roc-template-web-app'
}, {
name: 'Simple Roc React App',
description: 'A simple start on a React web application',
identifier: 'web-app-react',
repo: 'rocjs/roc-template-web-app-react'
}];
/**
* Command used to init a new Roc project.
*
* @param {rocCommandObject} parsedArguments - The Roc command object, uses parsedArguments from it.
*
* @returns {Promise} - Promise for the command.
*/
function init(_ref) {
let parsedArguments = _ref.parsedArguments;
let parsedOptions = _ref.parsedOptions;
let directory = _ref.directory;
var _parsedOptions$option = parsedOptions.options;
const list = _parsedOptions$option.list;
const force = _parsedOptions$option.force;
var _parsedArguments$argu = parsedArguments.arguments;
const name = _parsedArguments$argu.name;
const template = _parsedArguments$argu.template;
const version = _parsedArguments$argu.version;
// Get versions first
if (template && list) {
const toFetch = getTemplate(template);
return getTemplateVersion(toFetch, list);
}
// Make sure the directory is empty!
return checkFolder(force, name, directory).then(dir => {
if (!template) {
return interactiveMenu(dir, list);
}
return fetchTemplate(template, version, dir, list);
});
}
/*
* Helpers
*/
function isLocalTemplate() {
let template = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
return template.indexOf('.zip') === template.length - 4;
}
function getTemplateVersion(toFetch, list) {
return (0, _github.getVersions)(toFetch).then(versions => {
// Add master so we always have a way to install it
versions.push({ name: 'master' });
if (list) {
console.log('The available versions are:');
console.log(Object.keys(versions).map(index => ` ${ versions[index].name }`).join('\n'));
/* eslint-disable no-process-exit */
process.exit(0);
/* eslint-enable */
}
return Promise.resolve(versions);
});
}
function getTemplate(template) {
if (isLocalTemplate(template)) {
return template;
} else if (template.indexOf('/') === -1) {
const selectedTemplate = templates.find(elem => elem.identifier === template);
if (!selectedTemplate) {
console.log((0, _style.error)('Invalid template name given.'));
/* eslint-disable no-process-exit */
process.exit(1);
/* eslint-enable */
}
return selectedTemplate.repo;
}
return template;
}
function fetchTemplate(toFetch, selectVersion, directory, list) {
toFetch = getTemplate(toFetch);
const templateFetcher = isLocalTemplate(toFetch) ? (0, _unzip2.default)(toFetch) : getTemplateVersion(toFetch, list).then(versions => {
// If the name starts with a number we will automatically add 'v' infront of it to match Github default
if (selectVersion && !isNaN(Number(selectVersion.charAt(0))) && selectVersion.charAt(0) !== 'v') {
selectVersion = `v${ selectVersion }`;
}
const selectedVersion = versions.find(v => v.name === selectVersion);
const actualVersion = selectedVersion && selectedVersion.name || versions[0] && versions[0].name || 'master';
if (!selectedVersion && selectVersion) {
console.log((0, _style.warning)(`Selected template version not found, using ${ _chalk2.default.bold(actualVersion) }`));
} else if (!selectedVersion) {
console.log((0, _style.info)(`Using ${ _chalk2.default.bold(actualVersion) } as template version`));
}
return (0, _github.get)(toFetch, actualVersion);
});
return templateFetcher.then(dirPath => {
if (!(0, _general.validRocProject)(_path2.default.join(dirPath, 'template'))) {
/* eslint-disable no-process-exit */
console.log((0, _style.error)('Seems like this is not a Roc template.'));
process.exit(1);
/* eslint-enable */
} else {
console.log('\nInstalling template setup dependencies…');
return npmInstall(dirPath);
}
}).then(dirPath => {
_inquirer2.default.prompt(getPrompt(dirPath), answers => {
replaceTemplatedValues(answers, dirPath);
configureFiles(dirPath, directory);
console.log(`\nInstalling template dependencies… ` + `${ _chalk2.default.dim('(If this fails you can try to run npm install directly)') }`);
return npmInstall(directory).then(() => {
console.log((0, _style.ok)('\nSetup completed!\n'));
showCompletionMessage(dirPath);
});
});
}).catch(err => {
console.log((0, _style.error)('\nAn error occured during init!\n'));
console.error(err.message);
/* eslint-disable no-process-exit */
process.exit(1);
/* eslint-enable */
});
}
function getPrompt(dirPath) {
try {
return require(_path2.default.join(dirPath, 'roc.setup.js')).prompt;
} catch (err) {
return require('./helpers/default-prompt').defaultPrompt;
}
}
function showCompletionMessage(dirPath) {
try {
console.log(require(_path2.default.join(dirPath, 'roc.setup.js')).completionMessage);
} catch (err) {
// Do nothing
}
}
function replaceTemplatedValues(answers, dirPath) {
// 1. Replace content
Object.keys(answers).map(key => {
(0, _replace2.default)({
regex: `{{\\s*${ key }*\\s*}}`,
replacement: answers[key],
paths: [dirPath + '/template'],
recursive: true,
silent: true
});
});
// 2. Replace filenames
replaceTemplatedValuesInDirectory(answers, (0, _path.join)(dirPath, 'template'));
}
function replaceTemplatedValuesInDirectory(answers, dir) {
const matchTemplate = /{{\s*([^\s]+)*\s*}}/;
_fsExtra2.default.readdirSync(dir).forEach(file => {
let currentPath = (0, _path.join)(dir, file);
// Get potential "key" from filenames
const match = file.match(matchTemplate);
// Try to replace key if one was found
if (match) {
const toReplace = answers[match[1]];
if (!toReplace) {
console.log(`Could not find a value for the template value: {{ key }}`);
} else {
const newFilename = file.replace(matchTemplate, toReplace);
_fsExtra2.default.renameSync(currentPath, (0, _path.join)(dir, newFilename));
currentPath = (0, _path.join)(dir, newFilename);
}
}
if (_fsExtra2.default.lstatSync(currentPath).isDirectory()) {
replaceTemplatedValuesInDirectory(answers, currentPath);
}
});
}
function configureFiles(dirPath, directory) {
// Rename package.json to .roc for history purposes
_fsExtra2.default.renameSync(_path2.default.join(dirPath, 'package.json'), _path2.default.join(dirPath, 'template', '.roc'));
// Move everything inside template to the current working directory
_fsExtra2.default.copySync(_path2.default.join(dirPath, 'template'), directory);
}
function npmInstall(dirPath) {
return new Promise((resolve, reject) => {
// Run npm install
const npm = (0, _crossSpawn.spawn)('npm', ['install', '--loglevel=error'], {
cwd: dirPath,
stdio: 'inherit'
});
npm.on('close', function (code) {
if (code !== 0) {
return reject(new Error('npm install failed with status code: ' + code));
}
return resolve(dirPath);
});
});
}
function interactiveMenu(directory, list) {
return new Promise(resolve => {
const choices = templates.map(elem => ({ name: elem.name, value: elem.identifier }));
_inquirer2.default.prompt([{
type: 'rawlist',
name: 'option',
message: 'Selected a type',
choices: choices
}], answers => {
resolve(fetchTemplate(answers.option, undefined, directory, list));
});
});
}
function checkFolder() {
let force = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
let directoryName = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
let directory = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
return new Promise(resolve => {
const directoryPath = (0, _helpers.getAbsolutePath)(_path2.default.join(directory, directoryName));
_fsExtra2.default.mkdir(directoryPath, err => {
if (err) {
console.log((0, _style.warning)(`Found a folder named ${ _chalk2.default.underline(directoryPath) }, will try to use it.`), '\n');
}
if (!force && _fsExtra2.default.readdirSync(directoryPath).length > 0) {
_inquirer2.default.prompt([{
type: 'list',
name: 'selection',
message: `The directory '${ directoryPath }' is not empty, what do you want to do?`,
choices: [{
name: 'Create new folder',
value: 'new'
}, {
name: 'Run anyway ' + (0, _style.warning)('Warning: Some files might be overwritten.'),
value: 'force'
}, {
name: 'Abort',
value: 'abort'
}]
}], _ref2 => {
let selection = _ref2.selection;
if (selection === 'abort') {
/* eslint-disable no-process-exit */
process.exit(1);
/* eslint-enable */
} else if (selection === 'new') {
askForDirectory(directory, resolve);
} else if (selection === 'force') {
resolve(directoryPath);
}
});
} else {
resolve(directoryPath);
}
});
});
}
function askForDirectory(directory, resolve) {
_inquirer2.default.prompt([{
type: 'input',
name: 'name',
message: `What do you want to name the directory? (It will be created in '${ directory || process.cwd() }')`
}], _ref3 => {
let name = _ref3.name;
const directoryPath = (0, _helpers.getAbsolutePath)(name, directory);
_fsExtra2.default.mkdir(directoryPath, err => {
if (err) {
console.log((0, _style.warning)('The directory did already exists or was not empty.'), '\n');
return askForDirectory(resolve);
}
resolve(directoryPath);
});
});
}
//# sourceMappingURL=init.js.map