manz-cli
Version:
A simple cli command for create new projects and organize structure
350 lines (298 loc) • 10.1 kB
JavaScript
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const exec = require('child_process').execSync;
const inquirer = require('inquirer');
const ora = require('ora');
const colors = require('colors');
const npm = [];
const npmdev = [];
const npmglobal = [];
const srcPath = __dirname;
const choices = {
babel: ['No', 'Babel + preset-env (recomendado)'],
compatibility: ['No', 'Básica (>5%)', 'Media (>2% + last 1 + IE11)', 'Fuerte (>1% + last 2 + IE11)', 'Heavy (>1% + last 5 + IE8)'],
eslint: ['No', 'Sí, con eslint-config-google', 'Sí, con eslint-config-standard', 'Sí, con eslint-config-airbnb'],
git: ['No', 'Sí, inicializarlo'],
postcss: ['No', 'Sí (Autoprefixer)', 'Sí (Autoprefixer + Preset-env)', 'Sí (Autoprefixer + Preset-Env + Mixins + Font Magician + CleanCSS'],
stylelint: ['No', 'Sí, stylelint-config-standard', 'Sí, stylelint-config-recommended', 'Sí, stylelint-config-prettier'],
bundler: ['Ninguno', 'Parcel', 'Parcel (con Bundle-Visualiser)'],
framework: ['No', 'Sí, Vue.js'],
npminstall: ['No', 'Sí']
}
const execute = commandline => {
exec(commandline, (err, stdout, stderr) => {
console.log(stdout);
if (err)
console.error(err + ': ' + stderr);
});
};
const filewrite = (file, contents) => {
process.chdir(process.cwd());
fs.writeFileSync(file, contents);
}
const readfile = (file) => {
if (fs.existsSync(srcPath + path.sep + file))
return fs.readFileSync(srcPath + path.sep + file);
return false;
}
inquirer.prompt([
{
name: 'babel',
type: 'list',
message: '¿Quieres instalar Babel?',
choices: choices.babel,
default: 1
},
{
name: 'compatibility',
type: 'list',
message: '¿Quieres dotar de retrocompatibilidad a tu proyecto?',
choices: choices.compatibility,
default: 2
},
{
name: 'eslint',
type: 'list',
message: '¿Quieres revisar la calidad de código de Javascript?',
choices: choices.eslint,
default: 2
},
{
name: 'git',
type: 'list',
message: '¿Quieres utilizar Git en tu proyecto?',
choices: choices.git,
default: 1
},
{
name: 'postcss',
type: 'list',
message: '¿Quieres utilizar PostCSS en tu proyecto?',
choices: choices.postcss,
default: 3
},
{
name: 'stylelint',
type: 'list',
message: '¿Quieres revisar la calidad de código de CSS?',
choices: choices.stylelint,
default: 1
},
{
name: 'bundler',
type: 'list',
message: '¿Qué automatizador (bundler) quieres utilizar?',
choices: choices.bundler,
default: 1
},
{
name: 'framework',
type: 'list',
message: '¿Vas a utilizar algún framework Javascript?',
choices: choices.framework,
default: 0
},
{
name: 'npminstall',
type: 'list',
message: '¿Quieres instalar los paquetes del proyecto automáticamente?',
choices: choices.npminstall,
default: 0
}
]).then(answers => {
/* NPM */
if (!fs.existsSync('package.json'))
execute('npm init -y');
const package = JSON.parse(fs.readFileSync('package.json'));
npmdev.push('npm-run-all', 'cross-env');
/* Babel */
let option = choices.babel.indexOf(answers.babel);
if (option > 0) {
const babel = { presets: ["@babel/preset-env"] };
npmdev.push('@babel/cli', '@babel/core', '@babel/preset-env');
filewrite('.babelrc', JSON.stringify(babel, null, 4));
}
/* BrowsersList */
option = choices.compatibility.indexOf(answers.compatibility);
if (option > 0) {
const compatibility = [
`> 5%`,
`last 1 version\n> 2%\nIE 11`,
`last 2 version\n> 1%\nIE 11`,
`last 5 version\n> 1%\nIE 8`
];
filewrite('.browserslistrc', compatibility[option - 1]);
}
/* ESLint */
const eslint = JSON.parse(readfile('.eslintrc.json.sample'));
option = choices.eslint.indexOf(answers.eslint);
if (option > 0) {
eslint.extends.push("eslint:recommended");
const guides = ['google', 'standard', 'airbnb'];
eslint.extends.push(guides[option - 1]);
npmdev.push('eslint', 'eslint-plugin-import', 'eslint-plugin-node', 'eslint-plugin-promise', 'eslint-plugin-standard');
npmdev.push('eslint-config-' + guides[option - 1]);
}
/* Git */
option = choices.git.indexOf(answers.git);
if (option > 0) {
exec('git init');
filewrite('.gitignore', `node_modules\n.cache\ndist`);
}
/* PostCSS */
option = choices.postcss.indexOf(answers.postcss);
if (option > 0) {
const postcss = { plugins: {} };
switch (option) {
case 1:
postcss.plugins = { autoprefixer: true };
npmdev.push('autoprefixer');
break;
case 2:
postcss.plugins = {
"postcss-preset-env": {
stage: 3,
features: {
"nesting-rules": true,
"case-insensitive-attributes": true,
"hexadecimal-alpha-notation": true,
"place-properties": true
}
},
autoprefixer: true
};
npmdev.push('autoprefixer', 'postcss-preset-env');
break;
case 3:
postcss.plugins = {
"postcss-mixins": true,
"postcss-preset-env": {
stage: 3,
features: {
"nesting-rules": true,
"case-insensitive-attributes": true,
"hexadecimal-alpha-notation": true,
"place-properties": true
}
},
"postcss-font-magician": true,
autoprefixer: true,
"postcss-clean": true
};
npmdev.push('autoprefixer', 'postcss-preset-env', 'postcss-mixins', 'postcss-font-magician', 'postcss-clean');
break;
}
filewrite('.postcssrc', JSON.stringify(postcss, null, 4));
}
/* StyleLint */
option = choices.stylelint.indexOf(answers.stylelint);
if (option > 0) {
const stylelint = {
extends: [],
rules: {
"selector-nested-pattern": "^&",
"indentation": 2,
"no-descending-specificity": null,
"no-eol-whitespace": null,
"declaration-empty-line-before": null
}
};
switch (option) {
case 1:
stylelint.extends.push('stylelint-config-standard');
npmdev.push('stylelint-config-standard');
break;
case 2:
stylelint.extends.push('stylelint-config-recommended');
npmdev.push('stylelint-config-recommended');
break;
case 3:
stylelint.extends.push('stylelint-config-prettier');
npmdev.push('stylelint-config-prettier');
break;
}
filewrite('.stylelintrc', JSON.stringify(stylelint, null, 4));
}
/* Bundler */
option = choices.bundler.indexOf(answers.bundler);
if (option > 0) {
npmglobal.push('parcel-bundler');
package.scripts.dev = 'parcel serve src/index.html --open';
package.scripts.watch = 'parcel watch src/index.html';
package.scripts.build = 'rm -rf build/* && parcel build src/index.html -d build --global global --public-url /';
package.scripts.test = 'npx eslint src/*';
package.scripts['clean:cache'] = 'rm -rf .cache dist build';
package.scripts['clean:all'] = 'rm -rf node_modules package-lock.json .cache dist build';
package.scripts.deploy = 'git subtree push --prefix build origin gh-pages';
switch (option) {
case 2:
npmdev.push('parcel-plugin-bundle-visualiser');
break;
}
} else {
npmglobal.push('live-server');
package.scripts.dev = 'live-server src/index.html'
package.scripts.test = 'npx eslint src/*'
}
/* Framework */
option = choices.framework.indexOf(answers.framework);
if (option > 0) {
switch (option) {
case 1:
npmdev.push('@vue/component-compiler-utils', 'vue-hot-reload-api', 'vue-template-compiler');
npm.push('vue');
if (choices.eslint.indexOf(answers.eslint) > 0) {
npmdev.push('eslint-plugin-vue');
eslint.extends.push('plugin:vue/recommended');
eslint.plugins = ['vue'];
eslint.rules['vue/html-self-closing'] = 'off';
eslint.rules['vue/max-attributes-per-line'] = ['error', { singleline: 3, multiline: { max: 1, allowFirstLine: true }}];
}
break;
}
}
/* VSCode */
if (!fs.existsSync('.vscode'))
execute('mkdir .vscode');
const vscode = JSON.parse(readfile('settings.json.sample'));
if (choices.stylelint.indexOf(answers.stylelint) > 0) {
vscode['css.validate'] = false;
vscode['less.validate'] = false;
vscode['scss.validate'] = false;
}
if (choices.eslint.indexOf(answers.eslint) > 0) {
vscode['eslint.validate'] = ['javascript'];
if (choices.framework.indexOf(answers.framework) == 1) {
vscode['emmet.includeLanguages'] = { vue: 'html' };
vscode['eslint.validate'].push({ language: 'vue', autoFix: true });
}
}
filewrite('.vscode/settings.json', JSON.stringify(vscode, null, 4));
/* Finish */
filewrite('.eslintrc.json', JSON.stringify(eslint, null, 4));
filewrite('package.json', JSON.stringify(package, null, 4));
if (!fs.existsSync('src'))
execute('mkdir src');
/* NPM Install */
option = choices.npminstall.indexOf(answers.npminstall);
npminstall = (option == 0 ? '--package-lock-only' : '');
const oraOptions = {
color: 'yellow',
spinner: 'clock'
}
console.log("");
let spinner = ora({...oraOptions, text: 'Organizando archivos...'}).start();
spinner.succeed();
spinner.start('Configurando dependencias...');
execute(`npm install --loglevel=error ${npminstall} --save-dev ${npmdev.join(' ')}`);
spinner.succeed();
spinner.start('Configurando paquetes de producción...');
execute(`npm install --loglevel=error ${npminstall} ${npm.join(' ')}`);
spinner.succeed();
spinner.stop();
if (npmglobal.length > 0) {
console.log("\nRecuerda que debes instalar los siguientes paquetes globales (necesitarás permisos):".red);
console.log(" # ".green + `npm install -g ${npmglobal.join(' ')}`);
}
});