UNPKG

chameleon-tool

Version:

chameleon 脚手架工具

373 lines (343 loc) 12.5 kB
let fs = null; let path = null; let tpl = null; let inquirer = null; let ora = null; let shelljs = null; let fse = null; let chalk = null; let glob = null; const platformMap = require('./platform.json'); const platformTotal = Object.keys(platformMap).length; exports.name = 'init'; exports.usage = '[command] [options]'; exports.desc = 'initialize template for chameleon project'; const cmdOptions = { lang: 'cml', tpl: 'html', demo: 'blank' } /* istanbul ignore next */ exports.register = function (commander) { commander .option('-r, --root [root]', 'specify project root') .option('-g, --lang [cml|vue]', 'specify project template default language, example: cml init project -g vue ') .option('-t, --tpl [html|smarty]', 'specify project templateType, example: cml init project -t html') .option('-d, --demo [blank|todo]', 'specify init project demo, example: cml init project -d todo ') commander .action(function (...args) { /* eslint-disable */ fs = require('fs'); path = require('path'); tpl = require('chameleon-templates'); inquirer = require('inquirer'); ora = require('ora'); shelljs = require('shelljs'); fse = require('fs-extra'); glob = require('glob'); chalk = require('chalk'); /* eslint-disable */ // 不能删除 var options = args.pop(); // eslint-disable-line if (options.lang === 'vue') { cmdOptions.lang = options.lang; } if (options.tpl === 'smarty') { cmdOptions.tpl = options.tpl; } if (~['todo'].indexOf(options.demo)) { cmdOptions.demo = options.demo; } var type = args.shift(); if (type) { initMethod(type); } else { let questions = [{ type: 'list', name: 'type', message: 'Which do you want to init?', choices: [ 'project', 'page', 'component' ] }] inquirer.prompt(questions).then(answers => { initMethod(answers.type) }) } }) commander.on('--help', function() { var cmd = ` Commands: project initialize a chameleon project page initialize a chameleon page in project component initialize a chameleon component in project server initialize the php server for dev Examples: cml init project cml init page cml init component ` console.log(cmd) }) function initMethod(type) { if (!~['project', 'page', 'component'].indexOf(type)) { cml.log.error(`init type must in ['project', 'page', 'component']`); return; } if (type !== 'project') { cml.utils.checkProjectConfig(); } switch (type) { case 'project': initProject(); break; case 'page': initPage(); break; case 'component': initComponent(); break; default: break; } } function initProject() { let questions = [ { type: 'input', name: 'projectName', message: 'please input the name of project:', validate: function (value) { if (!value) { return 'project name can not be empty' } let nameReg = /^[0-9a-zA-Z_\-\.]+$/; if (!nameReg.test(value)) { return `project name characters must only in [0-9a-zA-Z_\-\.]` } if (fs.existsSync(value)) { return 'There is already a project with the same name in the current directory,please change one' } return true; } } ] inquirer.prompt(questions).then(answers => { let {projectName } = answers; let platforms = ['h5', 'weex', '微信小程序','支付宝小程序','百度小程序','qq小程序']; let templateType = cmdOptions.tpl; let templateLang = cmdOptions.lang; platforms = platforms.map(item => platformMap[item]); let pagedir = path.join(cml.projectRoot, projectName); let projectMap = { blank: tpl.blankDemoTpl, todo: tpl.todoDemoTpl } let projectTpl = projectMap[cmdOptions.demo]; fse.copySync(projectTpl, pagedir); // package.json文件中的name需要更改 var packagePath = path.join(pagedir, 'package.json'); let packageContent = JSON.parse(fs.readFileSync(packagePath, 'utf-8')); packageContent.name = projectName; fs.writeFileSync(packagePath, JSON.stringify(packageContent, '', 2)) // 修改配置文件 let configFile = path.join(pagedir, 'chameleon.config.js'); let content = fs.readFileSync(configFile, {encoding: 'utf-8'}).replace(/templateLang\s*:\s*["'](cml|vue)["']/g, function() { return `templateLang: "${templateLang}"` }) .replace(/templateType\s*:\s*["'](smarty|html)["']/g, function() { return `templateType: "${templateType}"` }) .replace(/platforms\s*:\s*\[(.+?)\]/g, function() { return `platforms: ${JSON.stringify(platforms)}` }) fs.writeFileSync(configFile, content); var npmignore = path.join(pagedir, '.npmignore'); // npm包中的.gitignore变成了.npmignore if (cml.utils.isFile(npmignore)) { fse.moveSync(npmignore, path.join(pagedir, '.gitignore')); } // 处理平台文件 if (platforms.length < platformTotal) { let { ignorePlatform, ignoreReg } = exports.getIgnorePlatform(platforms); let currentPlatforms = platforms; let currentReg = new RegExp(`\\.(${currentPlatforms.join('|')})\\.cml$`); // 处理.cml文件 let cmlFilePath = path.join(pagedir, '**/*.cml'); glob.sync(cmlFilePath).forEach(cfp => { // 删除忽略平台的文件 if (ignoreReg.test(cfp)) { fse.removeSync(cfp); } else { if (cfp.endsWith('.cml') && !currentReg.test(cfp)) { let content = fs.readFileSync(cfp, {encoding: 'utf-8'}); let splitContent = cml.utils.getScriptPart({content, cmlType: 'json'}); let jsonObj = JSON.parse(splitContent.content); ignorePlatform.forEach(item => { delete jsonObj[item]; }); content = content.replace(splitContent.content, `\n${JSON.stringify(jsonObj, null, 2)}\n`); fs.writeFileSync(cfp, content); } } }) // 处理 .interface文件 let interfaceFilePath = path.join(pagedir, '**/*.interface'); glob.sync(interfaceFilePath).forEach(ifp => { content = fs.readFileSync(ifp, {encoding: 'utf-8'}); ignorePlatform.forEach(item => { content = cml.utils.deleteScript({ content, cmlType: item }); }); fs.writeFileSync(ifp, content); }) } const installSpinner = ora('npm installing...').start() const install = shelljs.exec(`cd ${projectName} && npm install`, { silent: true }) if (install.code === 0) { installSpinner.color = 'green' installSpinner.succeed('install success') console.log(chalk.yellow('To get started:\n')) console.log(chalk.yellow(`cd ${projectName}\n`)) console.log(chalk.yellow(`cml dev\n`)) // installSpinner.succeed(`Please exec: cd ${projectName}; cml dev`) // console.log(`${install.stderr}${install.stdout}`) } else { installSpinner.color = 'red' installSpinner.fail(chalk.red('install fail, please exec npm install youself')) console.log(`${install.stderr}${install.stdout}`) } }) } function initPage() { let questions = [{ type: 'input', name: 'pageName', message: 'please input page name:', validate: function (value) { if (!value) { return 'page name can not be empty' } if (fs.existsSync(path.join(cml.projectRoot, `src/pages/${value}`))) { return 'There is already a page with the same name in the current project, please change one' } return true; } }] inquirer.prompt(questions).then(answers => { let {pageName} = answers; let pagedir = path.join(cml.projectRoot, `src/pages/${pageName}`) let UpperName = exports.toUpperCase(pageName); fs.readdirSync(tpl.pageTpl).forEach(fileName => { let filePath = path.join(tpl.pageTpl, fileName); let newFilePath = path.join(pagedir, fileName.replace('index', pageName)); let content = fs.readFileSync(filePath, {encoding: 'utf-8'}).replace(/Replace/ig, UpperName); if (cml.config.get().templateLang === 'vue') { content = content.replace(/<template>/, '<template lang="vue">') } content = exports.contentIgnoreHanle(content, 'cml'); fse.outputFile(newFilePath, content); }) cml.log.notice(`init page ${pageName} success!`) }) } function initComponent() { let questions = [{ type: 'list', name: 'componentType', message: 'please select the type of component', choices: [ 'Normal component', 'Polymorphic component', 'Polymorphic function' ] }, { type: 'input', name: 'componentName', message: 'please input component name:', validate: function (value) { if (!value) { return 'component name can not be empty' } if (fs.existsSync(path.join(cml.projectRoot, `src/components/${value}`))) { return 'There is already a component with the same name in the current project, please change one' } return true; } }] inquirer.prompt(questions).then(answers => { let {componentName, componentType} = answers; let comdir = path.join(cml.projectRoot, `src/components/${componentName}`); let comPathMap = { 'Normal component': 'component', 'Polymorphic component': 'interface-component', 'Polymorphic function': 'interface-js' } let tplPath = path.join(tpl.componentTpl, comPathMap[componentType]); let UpperName = exports.toUpperCase(componentName); let { ignoreReg } = exports.getIgnorePlatform(); fs.readdirSync(tplPath).forEach(fileName => { if (ignoreReg.test(fileName)) { return; } let filePath = path.join(tplPath, fileName); let newFilePath = path.join(comdir, fileName.replace('index', componentName)); let content = fs.readFileSync(filePath, {encoding: 'utf-8'}).replace(/Replace/ig, UpperName); if (cml.config.get().templateLang === 'vue') { content = content.replace(/<template>/, '<template lang="vue">') } if (newFilePath.endsWith('.cml')) { content = exports.contentIgnoreHanle(content, 'cml'); } if (newFilePath.endsWith('.interface')) { content = exports.contentIgnoreHanle(content, 'interface'); } fse.outputFile(newFilePath, content); }) cml.log.notice(`init component ${componentName} success!`) }) } } exports.toUpperCase = function (content) { content = content[0].toUpperCase() + content.slice(1); return content.replace(/-(\w)/ig, function(m, s1) { return s1.toUpperCase() }) } exports.getIgnorePlatform = function (platforms) { platforms = platforms || cml.config.get().platforms.map(item => item.trim()); let platformValues = Object.values(platformMap); let ignorePlatform = platformValues.filter(item => platforms.indexOf(item) === -1); let ignoreReg = new RegExp(`\\.(${ignorePlatform.join('|')})\\.cml$`); return { ignorePlatform, ignoreReg } } // 处理文件 exports.contentIgnoreHanle = function (content, type) { let { ignorePlatform } = exports.getIgnorePlatform(); if (type === 'interface') { ignorePlatform.forEach(item => { content = cml.utils.deleteScript({ content, cmlType: item }); }); } else if (type === 'cml') { let splitContent = cml.utils.getScriptPart({content, cmlType: 'json'}); if (splitContent) { let jsonObj = JSON.parse(splitContent.content); ignorePlatform.forEach(item => { delete jsonObj[item]; }); content = content.replace(splitContent.content, `\n${JSON.stringify(jsonObj, null, 2)}\n`); } } return content; }