code996
Version:
通过分析 Git commit 的时间分布,计算出项目的'996指数'
226 lines • 9.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnalyzeExecutor = void 0;
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const git_collector_1 = require("../../git/git-collector");
const git_parser_1 = require("../../git/git-parser");
const terminal_1 = require("../../utils/terminal");
const report_1 = require("./report");
const commit_guard_1 = require("../common/commit-guard");
/** 分析执行器,集中处理采集、解析与渲染流程 */
class AnalyzeExecutor {
/** 执行分析的主流程 */
static async execute(path, options) {
try {
const collector = new git_collector_1.GitCollector();
// 计算时间范围:优先使用用户输入,其次按最后一次提交回溯365天,最后退回到当前时间
const { since: effectiveSince, until: effectiveUntil, mode: rangeMode, note: rangeNote, } = await resolveTimeRange({ collector, path, options });
// 显示分析开始信息
console.log(chalk_1.default.blue('🔍 分析仓库:'), path || process.cwd());
switch (rangeMode) {
case 'all-time':
console.log(chalk_1.default.blue('📅 时间范围:'), '所有时间');
break;
case 'custom':
console.log(chalk_1.default.blue('📅 时间范围:'), `${effectiveSince} 至 ${effectiveUntil}`);
break;
case 'auto-last-commit':
console.log(chalk_1.default.blue('📅 时间范围:'), `${effectiveSince} 至 ${effectiveUntil}${rangeNote ? `(${rangeNote})` : ''}`);
break;
default:
console.log(chalk_1.default.blue('📅 时间范围:'), `${effectiveSince} 至 ${effectiveUntil}(按当前日期回溯)`);
}
console.log();
let authorFilter;
if (options.self) {
authorFilter = await resolveAuthorFilter(collector, path);
console.log(chalk_1.default.blue('🙋 作者过滤:'), authorFilter.displayLabel);
console.log();
}
// 构建统一的 Git 采集参数,保证所有步骤使用一致的过滤条件
const collectOptions = {
path,
since: effectiveSince,
until: effectiveUntil,
authorPattern: authorFilter?.pattern,
};
// 在正式分析前,先检查 commit 样本量是否达到最低要求
const hasEnoughCommits = await (0, commit_guard_1.ensureCommitSamples)(collector, collectOptions, 20, '分析');
if (!hasEnoughCommits) {
return;
}
// 创建进度指示器
const spinner = (0, ora_1.default)('📦 开始分析').start();
// 步骤1: 数据采集
const rawData = await collector.collect(collectOptions);
spinner.text = '⚙️ 正在解析数据...';
spinner.render();
// 步骤2: 数据解析与验证
const parsedData = git_parser_1.GitParser.parseGitData(rawData, undefined, effectiveSince, effectiveUntil);
const validation = git_parser_1.GitParser.validateData(parsedData);
if (!validation.isValid) {
spinner.fail('数据验证失败');
console.log(chalk_1.default.red('❌ 发现以下错误:'));
validation.errors.forEach((error) => {
console.log(` ${chalk_1.default.red('•')} ${error}`);
});
process.exit(1);
}
spinner.text = '📈 正在计算996指数...';
spinner.render();
// 步骤3: 计算996指数
const result = git_parser_1.GitParser.calculate996Index(parsedData);
spinner.succeed('分析完成!');
console.log();
// 若未指定时间范围,尝试回填实际的首尾提交时间
let actualSince;
let actualUntil;
if (!options.since && !options.until && !options.allTime) {
try {
actualSince = await collector.getFirstCommitDate(collectOptions);
actualUntil = await collector.getLastCommitDate(collectOptions);
}
catch {
console.log(chalk_1.default.yellow('⚠️ 无法获取实际时间范围,将使用默认显示'));
}
}
printResults(result, parsedData, rawData, options, effectiveSince, effectiveUntil, rangeMode);
}
catch (error) {
console.error(chalk_1.default.red('❌ 分析失败:'), error.message);
process.exit(1);
}
}
}
exports.AnalyzeExecutor = AnalyzeExecutor;
async function resolveTimeRange({ collector, path, options, }) {
if (options.allTime) {
// --all-time 时不传 since 和 until,让 git 返回所有数据
return {
mode: 'all-time',
};
}
// 处理 --year 参数
if (options.year) {
const yearRange = parseYearOption(options.year);
if (yearRange) {
return {
since: yearRange.since,
until: yearRange.until,
mode: 'custom',
note: yearRange.note,
};
}
}
if (options.since || options.until) {
const fallback = (0, terminal_1.calculateTimeRange)(false);
return {
since: options.since || fallback.since,
until: options.until || fallback.until,
mode: 'custom',
};
}
const baseOptions = {
path,
};
try {
const lastCommitDate = await collector.getLastCommitDate(baseOptions);
if (lastCommitDate) {
const untilDate = toUTCDate(lastCommitDate);
const sinceDate = new Date(untilDate.getTime());
sinceDate.setUTCDate(sinceDate.getUTCDate() - 365);
const baseline = Date.UTC(1970, 0, 1);
if (sinceDate.getTime() < baseline) {
sinceDate.setTime(baseline);
}
return {
since: formatUTCDate(sinceDate),
until: formatUTCDate(untilDate),
mode: 'auto-last-commit',
note: '以最后一次提交为基准回溯365天',
};
}
}
catch { }
const fallback = (0, terminal_1.calculateTimeRange)(false);
return {
since: fallback.since,
until: fallback.until,
mode: 'fallback',
};
}
/**
* 当启用 --self 时解析当前 Git 用户的信息,生成作者过滤正则
*/
async function resolveAuthorFilter(collector, path) {
const authorInfo = await collector.resolveSelfAuthor(path);
return {
pattern: authorInfo.pattern,
displayLabel: authorInfo.displayLabel,
};
}
/** 解析 --year 参数,支持单年和年份范围 */
function parseYearOption(yearStr) {
// 去除空格
yearStr = yearStr.trim();
// 匹配年份范围格式:2023-2025
const rangeMatch = yearStr.match(/^(\d{4})-(\d{4})$/);
if (rangeMatch) {
const startYear = parseInt(rangeMatch[1], 10);
const endYear = parseInt(rangeMatch[2], 10);
// 验证年份合法性
if (startYear < 1970 || endYear < 1970 || startYear > endYear) {
console.error(chalk_1.default.red('❌ 年份格式错误: 起始年份不能大于结束年份,且年份必须 >= 1970'));
process.exit(1);
}
return {
since: `${startYear}-01-01`,
until: `${endYear}-12-31`,
note: `${startYear}-${endYear}年`,
};
}
// 匹配单年格式:2025
const singleMatch = yearStr.match(/^(\d{4})$/);
if (singleMatch) {
const year = parseInt(singleMatch[1], 10);
// 验证年份合法性
if (year < 1970) {
console.error(chalk_1.default.red('❌ 年份格式错误: 年份必须 >= 1970'));
process.exit(1);
}
return {
since: `${year}-01-01`,
until: `${year}-12-31`,
note: `${year}年`,
};
}
// 格式不正确
console.error(chalk_1.default.red('❌ 年份格式错误: 请使用 YYYY 格式(如 2025)或 YYYY-YYYY 格式(如 2023-2025)'));
process.exit(1);
}
function toUTCDate(dateStr) {
const [year, month, day] = dateStr.split('-').map((value) => parseInt(value, 10));
return new Date(Date.UTC(year, (month || 1) - 1, day || 1));
}
function formatUTCDate(date) {
const year = date.getUTCFullYear();
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
const day = String(date.getUTCDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
/** 输出核心结果、时间分布与统计信息 */
function printResults(result, parsedData, rawData, options, since, until, rangeMode) {
(0, report_1.printCoreResults)(result, rawData, options, since, until, rangeMode);
(0, report_1.printDetailedAnalysis)(result, parsedData); // 新增:详细分析
(0, report_1.printWorkTimeSummary)(parsedData);
(0, report_1.printTimeDistribution)(parsedData);
(0, report_1.printWeekdayOvertime)(parsedData);
(0, report_1.printWeekendOvertime)(parsedData);
(0, report_1.printLateNightAnalysis)(parsedData);
(0, report_1.printRecommendation)(result, parsedData);
}
//# sourceMappingURL=analyze.js.map