UNPKG

code996

Version:

通过分析 Git commit 的时间分布,计算出项目的'996指数'

264 lines (256 loc) 13.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CLIManager = void 0; const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const child_process_1 = require("child_process"); const version_1 = require("../utils/version"); const notices_1 = require("./common/notices"); class CLIManager { /** 构造函数:初始化 Commander 实例并完成命令注册 */ constructor() { this.program = new commander_1.Command(); this.setupProgram(); } /** 配置 CLI 的基础信息与可用命令 */ setupProgram() { this.program .name('code996') .description('通过分析 Git commit 的时间分布,计算出项目的"996指数"') .version((0, version_1.getPackageVersion)(), '-v, --version', '显示版本号'); // 注册根命令默认行为,直接执行分析逻辑 this.setupDefaultAnalyzeAction(); this.addTrendCommand(); this.addHelpCommand(); // 错误处理 this.setupErrorHandling(); } /** 注册根命令,使用户直接运行 code996 即触发分析,并可选传入仓库路径 */ setupDefaultAnalyzeAction() { this.program .argument('[repoPath]', 'Git 仓库根目录路径(默认当前目录)') .option('-s, --since <date>', '开始日期 (YYYY-MM-DD)') .option('-u, --until <date>', '结束日期 (YYYY-MM-DD)') .option('-y, --year <year>', '指定年份或年份范围 (例如: 2025 或 2023-2025)') .option('--all-time', '查询所有时间的数据(默认为最近一年)') .option('--self', '仅统计当前 Git 用户的提交') .action(async (repoPath, options, command) => { const processedArgs = typeof repoPath === 'string' ? 1 : 0; const extraArgs = (command.args ?? []).slice(processedArgs); if (extraArgs.length > 0) { const invalid = extraArgs[0]; console.error(chalk_1.default.red(`错误: 未知命令 '${invalid}'`)); console.log('运行 code996 -h 查看可用命令'); process.exit(1); } const mergedOptions = this.mergeGlobalOptions(options); const targetPath = this.resolveTargetPath(repoPath, this.program.name()); await this.handleAnalyze(targetPath, mergedOptions); }); } /** 注册 trend 命令,分析月度趋势并支持自定义仓库路径 */ addTrendCommand() { const trendCmd = new commander_1.Command('trend') .description('分析月度996指数和工作时间的变化趋势') .option('-s, --since <date>', '开始日期 (YYYY-MM-DD)') .option('-u, --until <date>', '结束日期 (YYYY-MM-DD)') .option('-y, --year <year>', '指定年份或年份范围 (例如: 2025 或 2023-2025)') .option('--all-time', '查询所有时间的数据') .option('--self', '仅统计当前 Git 用户的提交') .argument('[repoPath]', 'Git 仓库根目录路径(默认当前目录)') .action(async (repoPath, options, command) => { const processedArgs = typeof repoPath === 'string' ? 1 : 0; const extraArgs = (command.args ?? []).slice(processedArgs); if (extraArgs.length > 0) { const invalid = extraArgs[0]; console.error(chalk_1.default.red(`错误: 未知命令 '${invalid}'`)); console.log('运行 code996 help 查看可用命令'); process.exit(1); } const targetPath = this.resolveTargetPath(repoPath, `${this.program.name()} trend`); await this.handleTrend(targetPath, options); }); this.program.addCommand(trendCmd); } /** 注册 help 命令,提供统一的帮助入口 */ addHelpCommand() { const helpCmd = new commander_1.Command('help').description('显示帮助信息').action(() => { this.showHelp(); }); this.program.addCommand(helpCmd); } /** 统一注册错误处理逻辑,提升用户体验 */ setupErrorHandling() { this.program.on('command:*', (operands) => { console.error(chalk_1.default.red(`错误: 未知命令 '${operands[0]}'`)); console.log('运行 code996 -h 查看可用命令'); process.exit(1); }); this.program.on('error', (err) => { console.error(chalk_1.default.red('发生错误:'), err.message); process.exit(1); }); } /** 处理分析流程的执行逻辑,targetPath 为已校验的 Git 根目录 */ async handleAnalyze(targetPath, options) { // 默认以当前工作目录作为分析目标,保持使用体验简单 // 导入analyze命令并执行 const mergedOptions = this.mergeGlobalOptions(options); const { AnalyzeExecutor } = await Promise.resolve().then(() => __importStar(require('./commands/analyze'))); await AnalyzeExecutor.execute(targetPath, mergedOptions); (0, notices_1.printGlobalNotices)(); } /** 处理趋势分析流程的执行逻辑,targetPath 为已校验的 Git 根目录 */ async handleTrend(targetPath, options) { // 导入trend命令并执行 const mergedOptions = this.mergeGlobalOptions(options); const { TrendExecutor } = await Promise.resolve().then(() => __importStar(require('./commands/trend'))); await TrendExecutor.execute(targetPath, mergedOptions); (0, notices_1.printGlobalNotices)(); } /** 合并全局选项(解决子命令无法直接读取根命令参数的问题) */ mergeGlobalOptions(options) { const globalOpts = this.program.opts(); return { ...options, self: options.self ?? globalOpts.self, allTime: options.allTime ?? globalOpts.allTime, since: options.since ?? globalOpts.since, until: options.until ?? globalOpts.until, year: options.year ?? globalOpts.year, }; } /** 解析并校验仓库路径,确保用户位于 Git 仓库根目录 */ resolveTargetPath(repoPathArg, commandLabel) { const candidatePath = path_1.default.resolve(repoPathArg ?? process.cwd()); if (!fs_1.default.existsSync(candidatePath)) { console.error(chalk_1.default.red('❌ 指定的目录不存在:'), candidatePath); console.log(chalk_1.default.yellow('请确认路径是否正确,或在 Git 仓库根目录运行命令。')); process.exit(1); } const stat = fs_1.default.statSync(candidatePath); if (!stat.isDirectory()) { console.error(chalk_1.default.red('❌ 指定路径不是目录:'), candidatePath); console.log(chalk_1.default.yellow('请传入 Git 仓库根目录,而不是单个文件。')); process.exit(1); } let gitRootRaw; try { gitRootRaw = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { cwd: candidatePath, stdio: ['ignore', 'pipe', 'pipe'], }) .toString() .trim(); } catch { console.error(chalk_1.default.red('❌ 未检测到有效的 Git 仓库:'), candidatePath); console.log(chalk_1.default.yellow('请在 Git 仓库根目录执行命令,或在命令末尾追加 Git 仓库路径,例如:')); console.log(chalk_1.default.cyan(` ${commandLabel} /path/to/your/repo`)); process.exit(1); } const normalizedCandidate = fs_1.default.realpathSync(candidatePath); const normalizedRoot = fs_1.default.realpathSync(gitRootRaw); if (normalizedCandidate !== normalizedRoot) { this.printGitRootWarning(normalizedCandidate, normalizedRoot, commandLabel); } return normalizedRoot; } /** 强提示当前路径非 Git 根目录,并指引用户的正确使用方式 */ printGitRootWarning(currentPath, rootPath, commandLabel) { console.error(chalk_1.default.bgRed.white(' ⚠️ 当前目录不是 Git 仓库根目录 ')); console.error(chalk_1.default.red(`当前目录: ${currentPath}`)); console.error(chalk_1.default.green(`仓库根目录: ${rootPath}`)); console.log(chalk_1.default.yellow('请在仓库根目录执行命令,或直接在命令末尾追加根目录路径,例如:')); console.log(chalk_1.default.cyan(` ${commandLabel} ${rootPath}`)); console.log(chalk_1.default.yellow('提示: 若你在子目录中,请先 cd 到上面的仓库根目录后再运行。')); process.exit(1); } /** 自定义帮助信息展示,补充常用示例 */ showHelp() { // 使用更紧凑的 CODE996 字符图,避免在窄终端中被截断 const banner = ` ████ ████ █████ ██████ ████ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █████ █████ █████ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ █████ ██████ ████ ████ ████ `; console.log(chalk_1.default.hex('#D72654')(banner)); console.log(`> 统计 Git 项目的 commit 时间分布,进而推导出项目的编码工作强度。 ${chalk_1.default.bold('使用方法:')} code996 [选项] code996 trend [选项] ${chalk_1.default.bold('命令:')} trend 查看月度996指数和工作时间的变化趋势 help 显示帮助信息 ${chalk_1.default.bold('全局选项:')} -v, --version 显示版本号 -h, --help 显示帮助信息 ${chalk_1.default.bold('分析选项:')} -s, --since <date> 开始日期 (YYYY-MM-DD) -u, --until <date> 结束日期 (YYYY-MM-DD) -y, --year <year> 指定年份或年份范围 (例如: 2025 或 2023-2025) --all-time 查询所有时间的数据(覆盖整个仓库历史) --self 仅统计当前 Git 用户的提交 ${chalk_1.default.bold('默认策略:')} 自动以最后一次提交为基准,回溯365天进行分析 ${chalk_1.default.bold('示例:')} ${chalk_1.default.gray('# 基础分析')} code996 # 分析最近一年 code996 --since 2024-01-01 # 从指定日期开始 code996 -y 2025 # 分析2025年整年 code996 -y 2023-2025 # 分析2023-2025年 code996 --all-time # 分析所有时间 ${chalk_1.default.gray('# 趋势分析')} code996 trend # 分析最近一年的月度趋势 code996 trend -y 2024 # 分析2024年各月趋势 code996 trend --all-time # 分析所有时间的月度趋势 ${chalk_1.default.bold('更多详情请访问:')} https://github.com/code996/code996 `); } /** 启动 CLI 参数解析入口 */ parse(argv) { this.program.parse(argv); } } exports.CLIManager = CLIManager; //# sourceMappingURL=index.js.map