查看原文
其他

开发一个Node命令行小玩具全过程--高颜统计工具

蓝色的秋风 秋风的笔记 2022-05-12

背景

命令行工具对于我们来说非常的熟悉,一些命令行的操作也极大的简化了我们的日常工作。本文就基于我写的一个Node命令行代码计数器来进行展开。

相信熟悉linux系统的,对于一些ps,grep,cp,mv…等命令用起来应该爱不释手,这也是我想要开发一个便捷命令行的初衷,其次就是记录一个完整开源小玩具的全过程。

命令行的特点:

  • 操作简便

  • 可视性强

看了一下当前的一些命令行有以下问题

  • 种类少 https://github.com/Towtow10/line-count

  • 颜值不够 https://github.com/AlDanial/cloc

  • 统计不太方便 https://github.com/ryanfowler/lines

因此这一款高颜值方便的统计工具诞生。

高颜图

玩具源码

https://github.com/hua1995116/linec

准备

第三方库

  • cli-table

  • colors

  • commander

  • ignore

dev库(用来测试)

  • chai

  • mocha

  • codecov

  • istanbu

Node兼容性

  • babel

静态文件

  • 语言映射库

  • 颜色库

思路

通过commander来获取用户的一些自定义配置

  1. program

  2.    .version('0.1.0')

  3.    .option('-i, --ignore [dir]', 'ignore dir')

  4.    .option('-p, --path [dir]', 'ignore dir')

  5.    .parse(process.argv);

Node遍历文件,每种语言行数信息

  1. function getFile(dirPath) {

  2.    const files = fs.readdirSync(dirPath);

  3.    files.forEach((item) => {

  4.        ...

  5.    })

  6. }

ignore过滤输出到cache

  1. function handleIgnode(cPath) {

  2.    try {

  3.        const currentPath = path.join(ROOTPATH, '.gitignore');

  4.        const fileData = fs.readFileSync(currentPath, 'utf-8');

  5.        const ignoreList = fileData.split('\n');

  6.        const filterList = filterData(ignoreList);

  7.        const ig = ignore().add(filterList);

  8.        return ig.ignores(cPath);

  9.    } catch (e) {

  10.        return false;

  11.    }

  12. }

遍历cache,统计max-line,进行colors

  1. function hanldeTable(){

  2.    ...

  3.    if (maxCount < langInfo[item].totalLines) {

  4.        maxCount = langInfo[item].totalLines;

  5.        maxIndex = index;

  6.    }

  7.    ...

  8. }

cli-table 输出展示

  1. function outputTbale() {

  2.    const {

  3.        header,

  4.        content,

  5.        bottom

  6.    } = initTable();

  7.    const {

  8.        totalFiles,

  9.        totalCode,

  10.        totalBlank,

  11.        tablesContent

  12.    } = hanldeTable();

  13.    ...

  14.    console.log(`T=${totalTime} s`, `(${fileSpeed} files/s`, `${lineSpeed} lines/s)`)

  15.    console.log(header.toString())

  16.    console.log(content.toString())

  17.    console.log(bottom.toString())

  18. }

改进

loading

对于多文件目录,提供loading

  1. lass StreamLoad {

  2.    constructor(option) {

  3.        this.stream = option.stream;

  4.        this.text = option.text;

  5.        this.clearLine = 0;

  6.    }

  7.    setValue(value) {

  8.        this.text = value;

  9.        this.render();

  10.    }

  11.    render() {

  12.        this.clear();

  13.        this.clearLine++;

  14.        this.stream.write(`read ${this.text} file\n`);

  15.    }

  16.    clear() {

  17.        if(!this.stream.isTTY) {

  18.            return this;

  19.        }

  20.        for (let i = 0; i < this.clearLine; i++) {

  21.            this.stream.moveCursor(0, -1);

  22.            this.stream.clearLine();

  23.            this.stream.cursorTo(0);

  24.        }

  25.        this.clearLine = 0;

  26.    }

  27. }

  28. const progress = new StreamLoad({

  29.    stream: process.stderr,

  30.    text: 0

  31. })

创建了一个实现loading的类。主要用到readline中的处理方法,详见https://nodejs.org/dist/latest-v8.x/docs/api/readline.html#readlinereadlinemovecursorstreamdx_dy

babel

对于低版本node的兼容

  1. cnpm i babel-cli

package.json

  1. "build": "./node_modules/.bin/babel src --out-dir lib"

测试用例

chai,mocha

用来测试遍历文件是否正确

  1. const path = require('path');

  2. const assert = require('chai').assert;

  3. const {getFileData} = require('../src/linec');

  4. describe('linec files test', () => {

  5.    it('can linec dir', () => {

  6.        const url = path.join(__dirname, '../example');

  7.        console.log(url);

  8.        const dirObj = JSON.stringify(getFileData(url));

  9.        const expectData = '{"CSS":{"file":1,"blankLines":0,"totalLines":4,"color":"#563d7c"},"JavaScript":{"file":1,"blankLines":0,"totalLines":1,"color":"#f1e05a"},"JSON":{"file":1,"blankLines":0,"totalLines":3,"color":"#fff"},"Markdown":{"file":1,"blankLines":0,"totalLines":1,"color":"#fff"}}';

  10.        assert.equal(dirObj, expectData);

  11.    })

  12. })

运行

  1. ./node_modules/mocha/bin/mocha

本项目中还添加了代码覆盖率的测试,因此是这样的

  1. "test": "./node_modules/.bin/istanbul cover node_modules/mocha/bin/_mocha && ./node_modules/.bin/codecov",

发布

Step1

打开https://www.npmjs.com/signup

注册一个账号

step2

如果有账号直接到这一步

  1. npm login

step3

在package.json中介入version

  1. {

  2.  "name": "linec",

  3.  "version": "1.2.4",

  4.  "description": "line count",

  5.  "main": "index.js",

  6.  ...

  7. }

step4

  1. npm publish

Tip:注意每次发版需要更改package.json 中的version,不然会发版失败哦。

命令行

package.json

  1. "bin": {

  2.    "linec": "./lib/index.js"

  3. },

本地项目命令行

  1. npm link

就可以使用linec 命令,将linec命令软连接到本地,linec这个名字可以自定义。

远端命令行

默认就是包名字,但是如果bin里面定义了一个名字,同上,可以修改名字。也就是包名可以和命令不一致,但是为了更方便的使用,个人建议统一包名和命令。

详情可以参考 http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html

持续集成测试&覆盖率的自动统计

https://travis-ci.org/

配置.travis.yml

  1. language: node_js

  2. node_js:

  3.  - "stable"

  4. sudo: false

  5. before_script:

  6.  - npm install

这个是我的配置,每次你的提交,只要含有npm run test命令,travis会自动调用,自动检测。

travis还有个好处,在别人给你提交pr的时候,可以自动运行测试用例,避免一些低级错误的发生。以下就是效果图。

https://codecov.io/gh

这是一个统计代码覆盖率的工具,在npm run test中添加他,在pr的时候可以看到覆盖率的统计

安装&使用

  1. $ npm install -g linec / cnpm install -g linec

基础用法

  1. $ linec

导出到html

  1. $ linec -o

运行完会在当前目录出现一个output.html

功能

  • 输出空行,实际行数,总行数

  • 支持400+语言

  • 显示遍历速度

  • 显示多种颜色

  • 支持导出html

工具源码(欢迎star) https://github.com/hua1995116/linec

效果图

基础模式

导出后打开html

结尾

以上就是全部内容,可能对于Node工具开发我可能还是处于初出茅庐的阶段,有更规范的操作,欢迎大佬们给我指正。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存