@afuteam-nx/plugin-exec-eslint
Version:
对代码仓库执行代码质量检查,支持批量项目。 输出结果包含仓库的 `eslint错误数` `空行数` `代码行数` `注释行数` `复杂度统计(不包含switchcase类型)`
249 lines • 12.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs = tslib_1.__importStar(require("fs"));
const path = tslib_1.__importStar(require("path"));
const child_process_1 = require("child_process");
const index_js_1 = tslib_1.__importDefault(require("./utils/index.js"));
function runExecutor(options) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
console.log('\n@afuteam-nx/plugin-exec-eslint插件开始执行\n', options);
const { localFileReposWithAFULintTypePath, localAllReposCodePath, resultPath, } = options;
function loadFileList() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const data = yield fs.promises.readFile(`${localFileReposWithAFULintTypePath}`, 'utf-8');
return JSON.parse(data);
});
}
// 执行具体的lint 返回结果
function runLint(lintType, lintPath) {
let lintresult = {
errors: 0,
warnings: 0,
total: 0,
blankLines: 0,
commentLines: 0,
codeLines: 0,
complexityDataLength: 0,
};
// 检查path是否存在
if (!fs.existsSync(lintPath)) {
return lintresult;
}
// 增加缓冲区大小到10MB
const res = (0, child_process_1.execSync)(`npx @afuteam/eslint-plugin-fe@latest --type=${lintType} --path=${lintPath}`, { encoding: 'utf8', maxBuffer: 1024 * 1024 * 10 });
// 受nx的影响 输出中包含了一些终端颜色代码 表现为 \u001b 开头的转义序列
// eslint-disable-next-line no-control-regex
const cleanRes = res.replace(/\u001b\[\d+m/g, '');
const errorsMatch = cleanRes.match(/Total errors:\s*(\d+)/);
const warningsMatch = cleanRes.match(/Total warnings:\s*(\d+)/);
const totalBlankLines = cleanRes.match(/Total totalBlankLines:\s*(\d+)/) || 0;
const totalCommentLines = cleanRes.match(/Total totalCommentLines:\s*(\d+)/) || 0;
const totalCodeLines = cleanRes.match(/Total totalCodeLines:\s*(\d+)/) || 0;
const complexityDataLength = cleanRes.match(/Total complexityDataLength:\s*(\d+)/) || 0;
try {
lintresult = {
errors: +errorsMatch[1],
warnings: +warningsMatch[1],
total: +errorsMatch[1] + +warningsMatch[1],
blankLines: +totalBlankLines[1],
commentLines: +totalCommentLines[1],
codeLines: +totalCodeLines[1],
complexityDataLength: +complexityDataLength[1],
};
}
catch (error) {
console.error('Failed to parse lint result:', error);
}
return lintresult;
}
// 项目维度累计数据之和
function summarizeErrorsAndWarnings(array) {
return array.map((item) => {
// 获取第一个键名作为工具集名称
const toolsetName = Object.keys(item)[0];
// 初始化错误和警告总数
let totalErrors = 0;
let totalWarnings = 0;
let totalBlankLines = 0;
let totalCommentLines = 0;
let totalCodeLines = 0;
let complexityDataLength = 0;
// 递归函数,累加 errors 和 warnings
function accumulateErrorsAndWarnings(info) {
if (typeof info === 'object' && info !== null) {
const objs = Object.keys(info);
objs.forEach((obj) => {
const value1 = info[obj];
if (typeof value1 === 'object') {
const value1_keys = Object.keys(value1);
value1_keys.forEach((key) => {
if (key === 'errors') {
totalErrors += value1[key];
}
if (key === 'warnings') {
totalWarnings += value1[key];
}
if (key === 'blankLines') {
totalBlankLines += value1[key];
}
if (key === 'commentLines') {
totalCommentLines += value1[key];
}
if (key === 'codeLines') {
totalCodeLines += value1[key];
}
if (key === 'complexityDataLength') {
complexityDataLength += value1[key];
}
// 递归调用
accumulateErrorsAndWarnings(value1[key]);
});
}
else {
if (obj === 'errors') {
totalErrors += info[obj];
}
if (obj === 'warnings') {
totalWarnings += info[obj];
}
if (obj === 'blankLines') {
totalBlankLines += info[obj];
}
if (obj === 'commentLines') {
totalCommentLines += info[obj];
}
if (obj === 'codeLines') {
totalCodeLines += info[obj];
}
if (obj === 'complexityDataLength') {
complexityDataLength += info[obj];
}
}
});
}
}
// 从 AFULintType 属性开始递归遍历
accumulateErrorsAndWarnings(item);
// 构建结果对象
// const summary = {
// [toolsetName]: {
// errors: totalErrors,
// warnings: totalWarnings,
// total: totalErrors + totalWarnings,
// blankLines: totalBlankLines,
// commentLines: totalCommentLines,
// codeLines: totalCodeLines,
// complexityDataLength: complexityDataLength,
// created_at: item.created_at || '',
// last_activity_at: item.last_activity_at || '',
// id: item.id || '',
// name: item.name || '',
// },
// };
const summary = {
errors: totalErrors,
warnings: totalWarnings,
total: totalErrors + totalWarnings,
blank_lines: totalBlankLines,
comment_lines: totalCommentLines,
code_lines: totalCodeLines,
complexity_data_ength: complexityDataLength,
repo_created_at: item.created_at || '',
repo_last_activity_at: item.last_activity_at || '',
repo_id: item.id || '',
repo_name: item.name || '',
};
return summary;
});
}
// 返回 error warn数
function lintProject(project) {
const { AFULintType, name } = project;
const alllintresult = {
[`${name}`]: {},
};
const AFULintTypeKeys = Object.keys(AFULintType);
const repositoryPath = path.join(localAllReposCodePath, '/', name);
// 标准的 根目录有 package.json
if (AFULintTypeKeys.length === 1 && AFULintTypeKeys.includes('root')) {
let lintRelativePath = repositoryPath + '/src';
if (!fs.existsSync(lintRelativePath)) {
lintRelativePath = repositoryPath + '/';
}
const res = runLint(AFULintType.root, lintRelativePath);
alllintresult[name] = res;
return alllintresult;
}
// 根目录 package.josn, 是 uniapp的
if (AFULintTypeKeys.length === 1 &&
AFULintTypeKeys.includes('root_uniappp')) {
const lintRelativePath = repositoryPath + '/';
const res = runLint(AFULintType.root_uniappp, lintRelativePath);
alllintresult[name] = res;
return alllintresult;
}
function handleCommonFileStruc(keys, curType, curRepoName, curPath) {
keys.forEach((key) => {
let lintRelativePath = curPath;
const lintRelativePathKey = curPath + `/${key}`;
const lintRelativePathSrc = lintRelativePathKey + '/src';
// src目录,有就用,没有就不用
if (fs.existsSync(lintRelativePathSrc)) {
lintRelativePath = lintRelativePathSrc;
}
// 如果key的目录存在,就用,不存在就当前路径计算
if (fs.existsSync(lintRelativePathKey)) {
lintRelativePath = lintRelativePathKey;
}
const curTypeKey = curType[key];
if (typeof curTypeKey === 'string') {
const res = runLint(curTypeKey, lintRelativePath);
alllintresult[curRepoName][key] = res;
}
if (typeof curTypeKey === 'object') {
handleCommonFileStruc(Object.keys(curTypeKey), curTypeKey, curRepoName, lintRelativePath);
}
});
}
if (AFULintTypeKeys.length > 0) {
handleCommonFileStruc(AFULintTypeKeys, AFULintType, name, repositoryPath);
}
return alllintresult;
}
function main() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const allProjects = yield loadFileList();
console.log(`共有项目 ${allProjects.length} 个`, '\n');
if (allProjects && allProjects.length > 0) {
const allData = [];
allProjects.forEach((project, index) => {
let projectLintData = lintProject(project);
const { id, created_at, last_activity_at, name, web_url } = project;
projectLintData = Object.assign(Object.assign({}, projectLintData), { id,
created_at,
last_activity_at,
name,
web_url });
console.log(`已完成 ${index + 1}/${allProjects.length} : ${project.name} \n`);
allData.push(projectLintData);
});
// 计算所有的结果
if (allData && allData.length > 0) {
console.log('开始计算最终结果...\n');
// 指定目录写入结果文件
index_js_1.default.writeRes2SomePath('allProjectsLintResultDetail.json', allData, resultPath);
const finalData = summarizeErrorsAndWarnings(allData);
index_js_1.default.writeRes2SomePath('allProjectsLintResult.json', finalData, resultPath);
}
}
});
}
yield main();
return {
success: true,
};
});
}
exports.default = runExecutor;
//# sourceMappingURL=executor.js.map