基于 Nodejs 实现统计工程代码量工具

217 阅读1分钟

定义一个模块 stat.js

const fs = require('fs');
const path = require('path');
class Stat {
    constructor(rootPath, opts) {
        this.countInfo = {
            filesCount: 0, //文件数量统计
            dirsCount: 0, //目录数量统计
            fileLineCount: 0, //全部文件行数统计
            maxFileLine: 0, //单个文件最大的行数
            classCount: 0, //类统计
            bigFilesList: [] //大文件列表
        }
        this.bigFileLimit = opts.bigFileLimit || 400; //大文件行数的定义
        this.rootPath = rootPath; //扫描的根目录
        this.ingoreDirs = opts.ingoreDirs || []; //忽略的目录
        this.ingoreFiles = opts.ingoreFiles || []; //忽略的文件
    }
    getFileCount() {

    }
    //从根目录递归收集文件和目录信息
    readFileList(dir, collectObj) {
        let {
            filesList,
            dirsList,
            bigFilesList
        } = collectObj
        const files = fs.readdirSync(dir);
        files.forEach((item, index) => {
            var fullPath = path.join(dir, item);
            const stat = fs.statSync(fullPath);
            if (stat.isDirectory()) {
                if (this.ingoreDirs.includes(item)) {
                    return;
                }
                dirsList.push(fullPath);
                this.readFileList(path.join(dir, item), collectObj); //递归读取文件
            } else {
                if (this.ingoreFiles.includes(item)) {
                    return;
                }
                //此时是文件
                let fileContent = fs.readFileSync(fullPath, 'utf-8');
                let fineLine = fileContent.split('\\n').length;
                if (fineLine > this.bigFileLimit) {
                    collectObj.bigFilesList.push(fullPath)
                }
                if (fineLine === 8963) {
                    console.log(fullPath)
                }
                collectObj.fileLinesList.push(fineLine);
                collectObj.classCount += this.getClassCountFromFileContent(fileContent);

                filesList.push(fullPath);
            }
        });
        return collectObj;

    }
    //获取文件的类个数,此处用 AST 替代 正则更准确
    getClassCountFromFileContent(fileContent) {
        let lines = fileContent.split('\\n');
        let count = 0;
        for (var line of lines) {
            if (/class\\s((.)*)/.exec(line)) {
                count++;
            }
        }
        return count;
    }
    //启动
    boot() {
        let collectObj = {
            filesList: [],
            dirsList: [],
            fileLinesList: [],
            classCount: 0,
            bigFilesList: []

        }
        this.readFileList(this.rootPath, collectObj);
        this.countInfo.filesCount = collectObj.filesList.length;
        this.countInfo.dirsCount = collectObj.dirsList.length;
        this.countInfo.maxFileLine = collectObj.fileLinesList.sort(function (a, b) {
            return b - a;
        })[0];
        // console.log( collectObj.fileLinesList)
        this.countInfo.fileLineCount = collectObj.fileLinesList.reduce(function (prev, cur) {
            return prev + cur;
        }, 0)
        this.countInfo.classCount = collectObj.classCount;
        this.countInfo.bigFilesList = collectObj.bigFilesList;
        return this;
    }
    // 打印统计信息
    logStatDesc(desc) {
        let logs = []

        desc ? logs.push(desc) : null;
        logs.push(`文件数量统计: ${this.countInfo.filesCount} 个`);
        logs.push(`目录数量统计: ${this.countInfo.dirsCount} 个`);
        logs.push(`代码总行数统计: ${this.countInfo.fileLineCount} 行`);
        logs.push(`单个文件最大行统计: ${this.countInfo.maxFileLine} 行`);
        // console.log(`JavaScript Class统计: ${this.countInfo.classCount} 个`);
        console.log(logs.join('\\n'));
        this.statLogs = logs;
        return this;
    }
    //打印工程建议
    logSuggestion() {
        let logs = []
        logs.push('---------------');
        logs.push('------- 工程建议 --------');

        logs.push(`这些文件超过 ${this.bigFileLimit} 行`);
        for (let file of this.countInfo.bigFilesList) {
            logs.push(file)
        }
        console.warn(logs.join('\\n'));
    }
    // 统计日志写入文件
    writeStatRecords(key, dirName) {
        fs.writeFileSync(path.join(dirName, key + '.txt'), this.statLogs.join('\\n'), 'utf8');
    }
    //合并多个统计实例
    mergeStat(statInstance) {
        for (let key in this.countInfo) {
            if (Object.prototype.toString.call(this.countInfo[key]) === '[object Number]') {
                this.countInfo[key] += statInstance.countInfo[key];
            }
            if (Object.prototype.toString.call(this.countInfo[key]) === '[object Array]') {
                this.countInfo[key].push(statInstance.countInfo[key]);
            }
        }
        return this;
    }
}

module.exports = Stat;

使用

const Stat = require('./stat');
const path = require('path');
const app = new Stat(path.join('/Users/jack/src/helloword', 'src'), {
    ingoreDirs: ['dist'],
    ingoreFiles:['eslint.json']
});
app.boot();
app.logStatDesc('helloword 统计】');
//app.logStatDesc('helloword 统计】');.writeStatRecords('./records')