├── README.md ├── lib ├── logger.js ├── generate.js ├── local-path.js ├── warnings.js └── check-version.js ├── bin ├── calamus ├── calamus-cli-vue.js └── calamus-cli-init.js ├── .gitignore ├── package.json └── src └── index.js /README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/logger.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/generate.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/local-path.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/warnings.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/check-version.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bin/calamus: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require = require('esm')(module /*, options*/); 4 | require('../src').cli(process.argv); -------------------------------------------------------------------------------- /bin/calamus-cli-vue.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const download = require("download-git-repo"); 3 | 4 | console.log('hello, commander') -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | .history 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | unpackage/ 16 | .history/ 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "calamus-cli", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "calamus": "calamus-cli" 9 | }, 10 | "bin": { 11 | "calamus-cli": "./bin/calamus" 12 | }, 13 | "publishConfig": { 14 | "access": "public" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC", 19 | "dependencies": { 20 | "boxen": "^4.1.0", 21 | "chalk": "^3.0.0", 22 | "esm": "^3.2.25", 23 | "execa": "^3.3.0", 24 | "inquirer": "^7.0.0", 25 | "listr": "^0.14.3", 26 | "log-symbols": "^3.0.0", 27 | "ora": "^4.0.3", 28 | "update-notifier": "^3.0.1" 29 | }, 30 | "devDependencies": { 31 | "commander": "^4.0.1", 32 | "download-git-repo": "^3.0.2", 33 | "fs": "0.0.1-security", 34 | "glob": "^7.1.6", 35 | "path": "^0.12.7", 36 | "rimraf": "^3.0.0", 37 | "tildify": "^2.0.0", 38 | "user-home": "^2.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /bin/calamus-cli-init.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const download = require('download-git-repo') //用于下载远程仓库至本地 支持GitHub、GitLab、Bitbucket 3 | const program = require('commander') //命令行处理工具 4 | const exists = require('fs').existsSync //node自带的fs模块下的existsSync方法,用于检测路径是否存在。(会阻塞) 5 | const path = require('path') //node自带的path模块,用于拼接路径 6 | const ora = require('ora') //用于命令行上的加载效果 7 | const home = require('user-home') //用于获取用户的根目录 8 | const tildify = require('tildify') //将绝对路径转换成带波浪符的路径 9 | const chalk = require('chalk')// 用于高亮终端打印出的信息 10 | const inquirer = require('inquirer') //用于命令行与开发者交互 11 | const rm = require('rimraf').sync // 相当于UNIX的“rm -rf”命令 12 | const logger = require('../lib/logger') //自定义工具-用于日志打印 13 | const generate = require('../lib/generate') //自定义工具-用于基于模板构建项目 14 | const checkVersion = require('../lib/check-version') //自定义工具-用于检测vue-cli版本的工具 15 | const warnings = require('../lib/warnings') //自定义工具-用于模板的警告 16 | const localPath = require('../lib/local-path') //自定义工具-用于路径的处理 17 | const isLocalPath = localPath.isLocalPath //判断是否是本地路径 18 | const getTemplatePath = localPath.getTemplatePath //获取本地模板的绝对路径 19 | 20 | program.usage('').parse(process.argv) 21 | 22 | let template = program.args[0]//项目名称 23 | const rawName = program.args[1] //项目构建目录名 24 | const inPlace = !rawName || rawName === '.' // 没写或者“.”,表示当前目录下构建项目 25 | const name = inPlace ? path.relative('../', process.cwd()) : rawName //如果在当前目录下构建项目,当前目录名为项目构建目录名,否则是当前目录下的子目录【rawName】为项目构建目录名 26 | const to = path.resolve(rawName || '.') //项目构建目录的绝对路径 27 | const clone = program.clone || false //是否采用clone模式,提供给“download-git-repo”的参数 28 | const tmp = path.join(home, '.vue-templates', template.replace(/[\/:]/g, '-')) //远程模板下载到本地的路径 29 | 30 | 31 | 32 | if (inPlace || exists(to)) { 33 | inquirer.prompt([{ 34 | type: 'confirm', 35 | message: inPlace 36 | ? 'Generate project in current directory?' 37 | : 'Target directory exists. Continue?', 38 | name: 'ok' 39 | }]).then(answers => { 40 | if (answers.ok) { 41 | run() 42 | } 43 | }).catch(logger.fatal) 44 | } else { 45 | run() 46 | } 47 | 48 | 49 | 50 | function run(){ 51 | //do something 52 | console.log('projectname',template,rawName) 53 | } 54 | 55 | /** 56 | * 定义下载模板并生产项目的函数 downloadAndGenerate 57 | */ 58 | function downloadAndGenerate(){ 59 | 60 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import program from 'commander'; //子命令 2 | import execa from 'execa'; //cli中调用外部命令 3 | import inquirer from 'inquirer'; //询问 4 | import ora from 'ora'; //终端加载效果 5 | import Listr from 'listr'; //步骤 6 | import chalk from 'chalk'; //高亮终端打印出来的信息 7 | import boxen from 'boxen'; //加边框 8 | import updateNotifier from 'update-notifier'; //update okg 9 | import pkg from '../package.json'; 10 | import logSymbols from 'log-symbols'; // 打印日志的特殊标志 11 | 12 | function checkVersion() { 13 | const notifier = updateNotifier({ pkg, updateCheckInterval: 0 }); 14 | if (notifier.update) { 15 | notifier.notify(); 16 | } 17 | } 18 | 19 | export function cli(args) { 20 | checkVersion(); 21 | //version 22 | program.version(pkg.version, '-v, --version,').usage(' [options]'); 23 | //init 24 | //vue 25 | program.version(pkg.version) 26 | .usage(' [options]') 27 | .command('init', 'init') 28 | .command('vue', 'vue') ; 29 | // .parse(process.argv) ; 30 | 31 | program.on('--help', () => { 32 | console.log(' Examples:') 33 | console.log() 34 | console.log(chalk.gray(' # create a new project with an official template')) 35 | console.log(' $ calamus-cli init webpack my-project') 36 | console.log() 37 | console.log(chalk.gray(' # create a new project straight from a github template')) 38 | console.log(' $ calamus-cli init username/repo my-project') 39 | console.log() 40 | }) 41 | 42 | //子命令 43 | program 44 | .command('start ') 45 | .option('-f, --fruit ', 'Fruit to be added') 46 | .description('Start cooking food') 47 | .action(function(food, option) { 48 | console.log(`run start command`); 49 | console.log(`argument: ${food}`); 50 | console.log(`option: fruit = ${option.fruit}`); 51 | }); 52 | 53 | //TODO:调用这个有问题 54 | program 55 | .command('npm-version') 56 | .description('Display npm version') 57 | .action(async function() { 58 | const { stdout } = await execa('vue -V').then((res)=>{ 59 | console.log('Npm version:',res); 60 | }).catch(error =>{ 61 | console.log('error',error) 62 | }); 63 | }); 64 | 65 | program 66 | .command('ask') 67 | .description('Ask some questions') 68 | .action(async function(option) { 69 | const answers = await inquirer.prompt([ 70 | { 71 | type: 'input', 72 | name: 'name', 73 | message: 'What is your name?' 74 | }, 75 | { 76 | type: 'confirm', 77 | name: 'isAdult', 78 | message: 'Are you over 18 years old?' 79 | }, 80 | { 81 | type: 'checkbox', 82 | name: 'favoriteFrameworks', 83 | choices: ['Vue', 'React', 'Angular'], 84 | message: 'What are you favorite frameworks?' 85 | }, 86 | { 87 | type: 'list', 88 | name: 'favoriteLanguage', 89 | choices: ['Chinese', 'English', 'Japanese'], 90 | message: 'What is you favorite language?' 91 | } 92 | ]); 93 | 94 | console.log(boxen(chalk.yellow(logSymbols.success + 'your answers:' ), { padding: 1 }) , '\n', answers); 95 | }); 96 | 97 | program 98 | .command('wait') 99 | .description('Wait 5 secords') 100 | .action(async function(option) { 101 | const spinner = ora('Waiting 5 seconds').start(); 102 | let count = 5; 103 | 104 | await new Promise(resolve => { 105 | let interval = setInterval(() => { 106 | if (count <= 0) { 107 | clearInterval(interval); 108 | spinner.stop(); 109 | resolve(); 110 | } else { 111 | count--; 112 | spinner.text = `Waiting ${count} seconds`; 113 | } 114 | }, 1000); 115 | }); 116 | }); 117 | 118 | 119 | program 120 | .command('steps') 121 | .description('some steps') 122 | .action(async function(option) { 123 | const tasks = new Listr([ 124 | { 125 | title: 'Run step 1', 126 | task: () => 127 | new Promise(resolve => { 128 | setTimeout(() => resolve('1 Done'), 1000); 129 | }) 130 | }, 131 | { 132 | title: 'Run step 2', 133 | task: () => 134 | new Promise((resolve) => { 135 | setTimeout(() => resolve('2 Done'), 1000); 136 | }) 137 | }, 138 | { 139 | title: 'Run step 3', 140 | task: () => 141 | new Promise((resolve, reject) => { 142 | setTimeout(() => reject(new Error('Oh, my god')), 1000); 143 | }) 144 | } 145 | ]); 146 | 147 | await tasks.run().catch(err => { 148 | console.error(err); 149 | }); 150 | }); 151 | 152 | program.parse(args); 153 | } --------------------------------------------------------------------------------