1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Node交互式命令行工具開發(fā)——自動(dòng)化文檔工具

        共 9618字,需瀏覽 20分鐘

         ·

        2021-04-10 13:06

        轉(zhuǎn)載自小磊

        https://segmentfault.com/a/1190000039749423

        nodejs開發(fā)命令行工具,流程相對簡單,但一套完整的命令行程序開發(fā)流程下來,還是需要下點(diǎn)功夫,網(wǎng)上資料大多零散,這篇教程意在整合一下完整的開發(fā)流程。

        npm上命令行開發(fā)相關(guān)包很多,例如minimistoptimist、nopt、commander.js、yargs等等,使用方法和效果類似。其中用得比較多的是TJ大神的commander和yargs,本文以commander為基礎(chǔ)講述,可以參考這篇教程,yargs教程可以參考阮大神的或者這一篇。

        另外,一個(gè)完整的命令行工具開發(fā),還需要了解process、shelljspath、linebyline等模塊,這些都是node基礎(chǔ)模塊或一些簡單模塊,非常簡單,就不多說了,另外如果你不想用回調(diào)函數(shù)處理異步還需要了解一下Promise、Generator函數(shù)。這是教程:i5ting大神的《深入淺出js(Node.js)異步流程控制》和阮大神的異步編程教程以及promise小人書,另外想嘗試ES7 stage3階段的async/await異步解決方案,可參考這篇教程,async/await解決方案需要babel轉(zhuǎn)碼,這是教程。本人喜歡async/await(哪個(gè)node開發(fā)者不喜歡呢?)但不喜歡倒騰,況且async/await本身就是Promise的語法糖,所以沒選擇使用,據(jù)江湖消息,nodejs將在今年晚些時(shí)候(10月份?)支持async/await,很是期待。

        以下是文章末尾實(shí)例用到的一些依賴。

        "dependencies": {
            "bluebird": "^3.4.1",
            "co": "^4.6.0",
            "colors": "^1.1.2",
            "commander": "^2.9.0",
            "dox": "^0.9.0",
            "handlebars": "^4.0.5",
            "linebyline": "^1.3.0",
            "mkdirp": "^0.5.1"
          }

        其中bluebird用于Promise化,TJ大神的co用于執(zhí)行Generator函數(shù),handlebars是一種模板,linebyline用于分行讀取文件,colors用于美化輸出,mkdirp用于創(chuàng)建目錄,另外教程中的示例是一款工具,可以自動(dòng)化生成數(shù)據(jù)庫和API接口的markdown文檔,并通過修改git hooks,使項(xiàng)目的每次commit都會(huì)自動(dòng)更新文檔,借助了TJ大神的dox模塊。

        安裝Node

        各操作系統(tǒng)下安裝見Nodejs官網(wǎng),安裝完成之后用node -v或者which node等命令測試安裝是否成功。which在命令行開發(fā)中是一個(gè)非常有用的命令,使用which命令確保你的系統(tǒng)中不存在名字相同的命令行工具,例如which commandName,例如which testdev命令返回空白那么說明testdev命令名稱還沒有被使用。

        初始化

        1. 新建一個(gè).js文件,即是你的命令要執(zhí)行的主程序入口文件,例如testdev.js。在文件第一行加入#!/usr/bin/env node指明系統(tǒng)在運(yùn)行這個(gè)文件的時(shí)候使用node作為解釋器,等價(jià)于node testdev.js命令。
        2. 初始化package.json文件,使用npm init命令根據(jù)提示信息創(chuàng)建,也可以是使用npm init -y使用默認(rèn)設(shè)置創(chuàng)建。創(chuàng)建完成之后需要修改package.json文件內(nèi)容加入"bin": {"testdev": "./testdev.js"}這條信息用于告訴npm你的命令(testdev)要執(zhí)行的腳本文件的路徑和名字,這里我們指定testdev命令的執(zhí)行文件為當(dāng)前目錄下的testdev.js文件。
        3. 為了方便測試在testdev.js文件中加入代碼console.log('hello world');,這里只是用于測試環(huán)境是否搭建成功,更加復(fù)雜的程序邏輯和過程需要按照實(shí)際情況進(jìn)行編寫

        測試

        使用npm link命令,可以在本地安裝剛剛創(chuàng)建的包,然后就可以用testdev來運(yùn)行命令了,如果正常的話在控制臺(tái)會(huì)打印出hello world

        commander

        TJ的commander非常簡潔,README.md已經(jīng)把使用方法寫的非常清晰。下面是例子中的代碼:

        const program = require('commander'),
          co = require('co');

        const appInfo = require('./../package.json'),
          asyncFunc = require('./../common/asyncfunc.js');

        program.allowUnknownOption();
        program.version(appInfo.version);

        program
          .command('init')
          .description('初始化當(dāng)前目錄doc.json文件')
          .action(() => co(asyncFunc.initAction));

        program
          .command('show')
          .description('顯示配置文件狀態(tài)')
          .action(() => co(asyncFunc.showAction));

        program
          .command('run')
          .description('啟動(dòng)程序')
          .action(() => co(asyncFunc.runAction));

        program
          .command('modifyhook')
          .description('修改項(xiàng)目下的hook文件')
          .action(() => co(asyncFunc.modifyhookAction));

        program
          .command('*')
          .action((env) => {
            console.error('不存在命令 "%s"', env);
          });

        program.on('--help', () => {
          console.log('  Examples:');
          console.log('');
          console.log('    $ createDOC --help');
          console.log('    $ createDOC -h');
          console.log('    $ createDOC show');
          console.log('');
        });

        program.parse(process.argv);

        定義了四個(gè)命令和個(gè)性化幫助說明。

        交互式命令行process

        commander只是實(shí)現(xiàn)了命令行參數(shù)與回復(fù)一對一的固定功能,也就是一個(gè)命令必然對應(yīng)一個(gè)回復(fù),那如何實(shí)現(xiàn)人機(jī)交互式的命令行呢,類似npm init或者eslint --init這樣的與用戶交互,交互之后根據(jù)用戶的不同需求反饋不同的結(jié)果呢。這里就需要node內(nèi)置的process模塊。

        這是我實(shí)現(xiàn)的一個(gè)init命令功能代碼:

        exports.initAction = function* () {
          try {
            var docPath = yield exists(process.cwd() + '/doc.json');
            if (docPath) {
              func.initRepl(config.coverInit, arr => {
                co(newDoc(arr));
              })
            } else {
              func.initRepl(config.newInit, arr => {
                co(newDoc(arr));
              })
            }
          } catch (err) {
            console.warn(err);
          }

        首先檢查doc.json文件是否存在,如果存在執(zhí)行覆蓋交互,如果不存在執(zhí)行生成交互,try...catch捕獲錯(cuò)誤。

        交互內(nèi)容配置如下:

            newInit:
            [
                {
                    title:'initConfirm',
                    description:'初始化createDOC,生成doc.json.確認(rèn)?(y/n)  ',
                    defaults'y'
                },
                {
                    title:'defaultConfirm',
                    description:'是否使用默認(rèn)配置.(y/n)  ',
                    defaults'y'
                },
                {
                    title:'showConfig',
                    description:'是否顯示doc.json當(dāng)前配置?(y/n)  ',
                    defaults'y'
                }
            ],
            coverInit:[
                {
                    title:'modifyConfirm',
                    description:'doc.json已存在,初始化將覆蓋文件.確認(rèn)?(y/n)  ',
                    defaults'y'
                },
                {
                    title:'defaultConfirm',
                    description:'是否使用默認(rèn)配置.(y/n)  ',
                    defaults'y'
                },
                {
                    title:'showConfig',
                    description:'是否顯示doc.json當(dāng)前配置?(y/n)  ',
                    defaults'y'
                }
            ],

        人機(jī)交互部分代碼也就是initRepl函數(shù)內(nèi)容如下:

        //初始化命令,人機(jī)交互控制
        exports.initRepl = function (init, func{
          var i = 1;
          var inputArr = [];
          var len = init.length;
          process.stdout.write(init[0].description);
          process.stdin.resume();
          process.stdin.setEncoding('utf-8');
          process.stdin.on('data', (chunk) => {
            chunk = chunk.replace(/[\s\n]/'');
            if (chunk !== 'y' && chunk !== 'Y' && chunk !== 'n' && chunk !== 'N') {
              console.log(config.colors.red('您輸入的命令是: ' + chunk));
              console.warn(config.colors.red('請輸入正確指令:y/n'));
              process.exit();
            }
            if (
              (init[i - 1].title === 'modifyConfirm' || init[i - 1].title === 'initConfirm') &&
              (chunk === 'n' || chunk === 'N')
            ) {
              process.exit();
            }
            var inputJson = {
              title: init[i - 1].title,
              value: chunk,
            };
            inputArr.push(inputJson);
            if ((len--) > 1) {
              process.stdout.write(init[i++].description)
            } else {
              process.stdin.pause();
              func(inputArr);
            }
          });
        }

        人機(jī)交互才用向用戶提問根據(jù)用戶不同輸入產(chǎn)生不同結(jié)果的形式進(jìn)行,順序讀取提問列表并記錄用戶輸入結(jié)果,如果用戶輸入n/N則終止交互,用戶輸入非法字符(除y/Y/n/N以外)提示輸入命令錯(cuò)誤。

        文檔自動(dòng)化

        文檔自動(dòng)化,其中數(shù)據(jù)庫文檔自動(dòng)化,才用依賴sequelize的方法手寫(根據(jù)需求不同自行編寫邏輯),API文檔才用TJ的dox也很簡單。由于此處代碼與命令行功能相關(guān)度不大,請讀者自行去示例地址查看代碼。

        示例地址

        github地址:https://github.com/threerocks/buildDOC

        npm地址:https://www.npmjs.com/package/createDOC

        最后

        歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
        回復(fù)「算法」,加入前端算法源碼編程群,每日一刷(工作日),每題瓶子君都會(huì)很認(rèn)真的解答喲!
        回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
        回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
        如果這篇文章對你有幫助,在看」是最大的支持
        》》面試官也在看的算法資料《《
        “在看和轉(zhuǎn)發(fā)”就是最大的支持
        瀏覽 54
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            操逼免费片 | 色色网视频 | 天天淫淫网 | 《韩国激情合集无删减 | 国产精品色网 | 男人手机天堂 | 欧美色图1 | 成人免费毛片 免费 | 在线亚洲电影 | 日韩香蕉网 |