Last active
April 3, 2018 10:34
-
-
Save dimensi/fccb82e4b1505a786af8a9b38e0136e3 to your computer and use it in GitHub Desktop.
MakeBlock generator for vue components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
const inquirer = require('inquirer'); | |
const program = require('commander'); | |
const changeCase = require('change-case'); | |
const fs = require('fs'); | |
const path = require('path'); | |
const { promisify } = require('util'); | |
const prettier = require('prettier'); | |
const fsAccess = promisify(fs.access); | |
const fsMkDir = promisify(fs.mkdir); | |
const fsWriteFile = promisify(fs.writeFile); | |
const fsReadDir = promisify(fs.readdir); | |
const folders = { | |
page: path.join(__dirname, '..', 'src/views/pages'), | |
block: path.join(__dirname, '..', 'src/views/components'), | |
element: path.join(__dirname, '..', 'src/views/elements'), | |
}; | |
const baseFunctions = { | |
components: 'components: {},', | |
props: 'props: {},', | |
data: `data() { | |
return { | |
}; | |
},`, | |
computed: 'computed: {},', | |
watch: 'watch: {},', | |
created: 'created() {},', | |
mounted: 'mounted() {},', | |
methods: 'methods: {},', | |
}; | |
const generateFunctions = (arrFunc) => { | |
const joinSymbol = '\n'; | |
if (arrFunc === 'all') { | |
return Object.keys(baseFunctions).map(name => baseFunctions[name]).join(joinSymbol); | |
} | |
return arrFunc.map(name => baseFunctions[name]).join(joinSymbol); | |
}; | |
let prettierOptions = {}; | |
const fileSources = { | |
vue: (blockName, arrFunc) => ` | |
<template> | |
<div class="${changeCase.paramCase(blockName)}"></div> | |
</template> | |
<script> | |
${prettier.format(`export default { | |
name: '${changeCase.paramCase(blockName)}', | |
${generateFunctions(arrFunc)} | |
};`, prettierOptions).trim()} | |
</script> | |
<style lang="scss"> | |
.${changeCase.paramCase(blockName)} { | |
display: block; | |
} | |
</style> | |
`, | |
}; | |
class MakeBlock { | |
constructor(options) { | |
this.options = options; | |
} | |
async directoryOrFileExist(blockPath, blockName) { | |
try { | |
await fsAccess(blockPath, fs.constants.W_OK); | |
throw `Error >>> Данный файл или директория уже существует ${blockName || blockPath}`; | |
} catch (err) { | |
if (err instanceof Error && err.code === 'ENOENT') { | |
return true; | |
} | |
throw err; | |
} | |
} | |
async createDir(dirPath) { | |
try { | |
await fsMkDir(dirPath); | |
return true; | |
} catch (err) { | |
throw `Error >>> Данная папка уже существует ${dirPath}`; | |
} | |
} | |
async createFiles(blockPath, blockName) { | |
const files = []; | |
const functions = this.options.defaultFunctions ? 'all' : this.options.functions; | |
for (const ext in fileSources) { | |
const fileSource = fileSources[ext](blockName, functions).trim(); | |
const filename = `${blockName}.${ext}`; | |
const filePath = path.join(blockPath, filename); | |
try { | |
await this.directoryOrFileExist(filePath); | |
} catch (err) { | |
throw `Error >>> Данный файл уже существует ${filePath}`; | |
} | |
files.push(fsWriteFile(filePath, fileSource, 'utf-8')); | |
} | |
return await Promise.all(files); | |
} | |
async getFiles(blockPath, blockName) { | |
try { | |
const files = await fsReadDir(blockPath); | |
const file = files.filter(file => file.includes(blockName)); | |
console.log('\n'); | |
console.log(`Блок ${blockName} создан`); | |
console.log('-'.repeat(48)); | |
file.forEach((name) => { | |
console.log(name); | |
}); | |
console.log('#'.repeat(48)); | |
return true; | |
} catch (err) { | |
console.error(err); | |
throw err; | |
} | |
} | |
async makeBlock(blockName) { | |
let blockPath = path.join(folders[this.options.typeBlock]); | |
if (this.options.createWithDir) { | |
blockPath = path.join(folders[this.options.typeBlock], blockName); | |
} | |
if (this.options.createWithDir) { | |
await this.directoryOrFileExist(blockPath); | |
await this.createDir(blockPath); | |
} | |
try { | |
await this.createFiles(blockPath, blockName); | |
} catch (err) { | |
console.log(err); | |
return false; | |
} | |
await this.getFiles(blockPath, blockName); | |
return true; | |
} | |
create() { | |
const blocks = this.options.blockName; | |
if (Array.isArray(blocks)) { | |
const files = blocks.map(name => this.makeBlock(name)); | |
return Promise.all(files); | |
} | |
return this.makeBlock(blocks); | |
} | |
} | |
console.log('Vue component generator'); | |
const questions = [ | |
{ | |
type: 'input', | |
name: 'blockName', | |
message: 'Название блока', | |
validate(answer) { | |
if (!/^(\d|\w|-)+$/.test(answer)) { | |
return 'Введите имя в правильном формате'; | |
} | |
if (!answer.length) { | |
return 'Нужно указать имя блока'; | |
} | |
return true; | |
}, | |
}, | |
{ | |
type: 'list', | |
name: 'typeBlock', | |
message: 'Тип блока?', | |
choices: [{ | |
name: 'Элемент', | |
value: 'element', | |
}, { | |
name: 'Компонент', | |
value: 'block', | |
}, { | |
name: 'Страница', | |
value: 'page', | |
}], | |
}, | |
{ | |
type: 'confirm', | |
name: 'createWithDir', | |
message: 'Создавать с папкой?', | |
default: true, | |
}, | |
{ | |
type: 'confirm', | |
name: 'defaultFunctions', | |
message: 'Функции по умолчанию?', | |
default: true, | |
}, | |
{ | |
type: 'checkbox', | |
name: 'functions', | |
message: 'Выберите функции', | |
choices: [ | |
{ | |
name: 'components', | |
}, | |
{ | |
name: 'props', | |
}, | |
{ | |
name: 'data', | |
}, | |
{ | |
name: 'computed', | |
}, | |
{ | |
name: 'watch', | |
}, | |
{ | |
name: 'created', | |
}, | |
{ | |
name: 'mounted', | |
}, | |
{ | |
name: 'methods', | |
}, | |
], | |
when(answers) { | |
return !answers.defaultFunctions; | |
}, | |
}, | |
]; | |
async function createBlockWithInterface() { | |
const data = await inquirer.prompt(questions); | |
const createBlock = new MakeBlock(data); | |
return createBlock.create(); | |
} | |
prettier.resolveConfig(process.cwd()).then((options) => { | |
prettierOptions = options; | |
program | |
.version('1.0.0') | |
.usage('<name-block ...>') | |
.arguments('[name-block...]') | |
.option('-t, --type [type]', 'Тип компонента (block|element) [block]', 'block') | |
.option('--no-folder', 'Без папки') | |
.action((blocks, commands) => { | |
for (const block of blocks) { | |
if (!/^(\d|\w|-)+$/.test(block)) { | |
console.error('Введите имя в правильном формате'); | |
return false; | |
} | |
} | |
const createBlock = new MakeBlock({ | |
blockName: blocks, | |
typeBlock: commands.type || 'block', | |
createWithDir: commands.folder, | |
defaultFunctions: true, | |
}); | |
createBlock.create() | |
.catch((err) => { | |
console.log(err); | |
}); | |
}) | |
.parse(process.argv); | |
if (!program.args.length) { | |
createBlockWithInterface(); | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment