UNPKG

mp-lens

Version:

微信小程序分析工具 (Unused Code, Dependencies, Visualization)

155 lines 7.39 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const chalk_1 = __importDefault(require("chalk")); const commander_1 = require("commander"); const clean_1 = require("./commands/clean"); const cpd_1 = require("./commands/cpd"); const diffBundle_1 = require("./commands/diffBundle"); const graph_1 = require("./commands/graph"); const lint_1 = require("./commands/lint"); const purgewxss_1 = require("./commands/purgewxss"); const telemetry_1 = require("./telemetry"); const debug_logger_1 = require("./utils/debug-logger"); const errors_1 = require("./utils/errors"); const version_check_1 = require("./utils/version-check"); const version_1 = require("./version"); const program = new commander_1.Command(); // Check for updates before command execution (0, version_check_1.checkForUpdates)(); // Helper to setup logger based on global options function setupLogger(globalOptions) { // Configure logger verbosity if (globalOptions.trace) { debug_logger_1.logger.setLevel(debug_logger_1.LogLevel.TRACE); } else if (globalOptions.verboseLevel > 0) { // Ensure level is within bounds const level = Math.max(0, Math.min(3, globalOptions.verboseLevel)); debug_logger_1.logger.setLevel(level); } else if (globalOptions.verbose) { debug_logger_1.logger.setLevel(debug_logger_1.LogLevel.NORMAL); // or DEBUG? Let's use NORMAL } else { debug_logger_1.logger.setLevel(debug_logger_1.LogLevel.ESSENTIAL); } // Setting project root will happen within command handlers now // logger.setProjectRoot(resolvedProjectPath); debug_logger_1.logger.debug(`Logger level set to: ${debug_logger_1.logger.getLevel()}`); } // Centralized error handler for commands function commandErrorHandler(errorMessage, errorStack) { debug_logger_1.logger.error(errorMessage); if (errorStack) { debug_logger_1.logger.debug(errorStack); } debug_logger_1.logger.warn(chalk_1.default.yellow('💡 如果您需要帮助,或怀疑这是一个程序缺陷,请前往 https://github.com/chess99/mp-lens/issues 提交issue。')); // 不再直接调用 process.exit(1),而是抛出异常,让主流程自然结束 process.exitCode = 1; } // Define the global options program .version(version_1.version) .description('微信小程序依赖分析与清理工具') .option('-p, --project <path>', '指定项目的根目录', process.cwd()) .option('-v, --verbose', '显示更详细的日志输出') .option('--verbose-level <level>', '详细日志级别 (0=基本, 1=正常, 2=详细, 3=追踪)', (val) => parseInt(val, 10), 0) .option('--trace', '启用最详细的日志输出 (等同于 --verbose-level 3)') .option('--config <path>', '指定配置文件的路径') .option('--miniapp-root <path>', '指定小程序代码所在的子目录(相对于项目根目录)') .option('--entry-file <path>', '指定入口文件路径(相对于小程序根目录,默认为app.json)') .option('--types <types>', '指定要分析的文件类型 (覆盖配置文件)') .option('--exclude <pattern>', '排除某些文件/目录 (覆盖配置文件)', (value, previous) => previous.concat([value]), []) .option('--essential-files <files>', '指定视为必要的文件,用逗号分隔 (覆盖配置文件)') .option('--include-assets', '在分析和清理中包含图片等资源文件 (默认不包含)', false) .option('--telemetry <boolean>', '是否启用遥测 (默认 true)', true); function withTelemetryAction(commandName, action) { return async (...args) => { const cliOptions = program.opts(); // 初始化遥测服务,并传入命令行选项 telemetry_1.telemetry.init({ telemetry: cliOptions.telemetry }); const commandArgs = process.argv.slice(2); telemetry_1.telemetry.capture({ event: 'command', command: commandName, version: version_1.version, args: commandArgs, }); setupLogger(cliOptions); try { await action(cliOptions, ...args); } catch (error) { if (error instanceof errors_1.HandledError) { // 上报用户遇到的预期问题 telemetry_1.telemetry.capture({ event: 'user-issue', command: commandName, issueType: (0, telemetry_1.inferIssueType)(error.message), issueMessage: error.message, version: version_1.version, args: commandArgs, }); } else { // 上报系统错误 telemetry_1.telemetry.capture({ event: 'error', command: commandName, version: version_1.version, errorMessage: error.message, stack: error.stack, args: commandArgs, }); } commandErrorHandler(`Command failed: ${error.message}`, error.stack); } finally { await (0, telemetry_1.shutdownTelemetry)(); } }; } // graph command program .command('graph') .description('生成依赖关系图的可视化文件') .option('-f, --format <format>', '输出格式 (html|json)', 'html') .option('-o, --output <file>', '保存图文件的路径') .action(withTelemetryAction('graph', graph_1.graph)); // clean command program .command('clean') .description('分析项目并删除未使用的文件。默认会先列出文件并提示确认。') .option('--write', '实际写入更改(删除文件)', false) .action(withTelemetryAction('clean', clean_1.clean)); // lint command program .command('lint [path]') .description('分析小程序项目中组件声明与使用的一致性') .option('--fix', '自动修复JSON文件中"声明但未使用"的问题') .action(withTelemetryAction('lint', lint_1.lint)); program .command('purgewxss [wxss-file-path]') .description('分析 WXML/WXSS 并使用 PurgeCSS 移除未使用的 CSS。未指定路径则处理项目中所有 .wxss 文件。') .option('--write', '实际写入对 WXSS 文件的更改。') .action(withTelemetryAction('purgewxss', purgewxss_1.purgewxss)); program .command('cpd') .description('检测小程序项目中的重复代码(基于 jscpd,自动识别 miniappRoot)') .option('--minLines <number>', '最小重复行数', parseInt) .option('--minTokens <number>', '最小重复 token 数', parseInt) .option('--reporters <string>', '报告输出格式(如 html,console)') .action(withTelemetryAction('cpd', cpd_1.cpd)); program .command('diff') .description('比较两个 Git 分支或提交之间的包大小差异') .option('--base <string>', '基准分支或提交 (默认为 master)') .option('--target <string>', '目标分支或提交 (默认为 HEAD)') .action(withTelemetryAction('diff', diffBundle_1.diffBundle)); // Parse arguments program.parse(process.argv); //# sourceMappingURL=cli.js.map