定义一个模块 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')