UNPKG

i18n-xy

Version:

自动提取React项目中的中文字符串并进行国际化的CLI工具

1,350 lines (1,333 loc) 126 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/config/default.config.ts var defaultConfig; var init_default_config = __esm({ "src/config/default.config.ts"() { "use strict"; defaultConfig = { // 基础语言配置 locale: "zh-CN", fallbackLocale: "en-US", outputDir: "locales", // tempDir: undefined, // 可选,不设置则直接修改源文件 // 文件处理配置 include: [ "src/**/*.{js,jsx,ts,tsx}", "pages/**/*.{js,jsx,ts,tsx}", "components/**/*.{js,jsx,ts,tsx}" ], exclude: [ "node_modules/**", "dist/**", "build/**", "**/*.test.{js,jsx,ts,tsx}", "**/*.spec.{js,jsx,ts,tsx}" ], // Key 生成配置 keyGeneration: { maxChineseLength: 10, // 最大汉字长度 hashLength: 6, // 哈希长度 maxRetryCount: 5, // 最大重试次数 reuseExistingKey: true, // 默认重复使用相同文案的key duplicateKeySuffix: "hash", // 重复key后缀模式,默认hash keyPrefix: "", // key前缀,默认为空 separator: "_", // 连接符,默认下划线 pinyinOptions: { // 拼音转换选项 toneType: "none", // 不带声调 type: "array" // 返回数组格式 } }, // 输出配置 output: { prettyJson: true, // 格式化 JSON 输出 localeFileName: "{locale}.json" // 语言文件名格式 }, // 日志配置 logging: { enabled: true, // 默认启用日志 level: "normal" // 默认正常级别 }, // 替换配置 replacement: { functionName: "$t", // 默认替换函数名 quoteType: "single", // 默认使用单引号 autoImport: { enabled: false, // 默认不启用自动引入 insertPosition: "afterImports", // 默认在import语句后插入 imports: {} } }, // 翻译配置 translation: { enabled: false, // 默认不启用翻译功能 provider: "baidu", // 默认使用百度翻译 defaultSourceLang: "zh", // 默认源语言:中文 defaultTargetLang: "en", // 默认目标语言:英文 concurrency: 5, // 默认并发数:5 (降低并发数避免API限制) retryTimes: 3, // 默认重试次数:3次(不包括第一次) retryDelay: 1e3, // 默认重试延迟:1秒 batchDelay: 500, // 默认批次延迟:0.5秒 baidu: { appid: "", // 需要用户配置 key: "" // 需要用户配置 } } }; } }); // src/utils/fs.ts function readFile2(filePath, encoding = "utf-8") { const absPath = path.resolve(process.cwd(), filePath); return fs.readFile(absPath, encoding); } function writeFile(filePath, data) { const absPath = path.resolve(process.cwd(), filePath); return fs.outputFile(absPath, data); } function writeFileWithTempDir(filePath, data, tempDir) { let targetPath; if (tempDir) { const relativePath = path.relative(process.cwd(), filePath); targetPath = path.resolve(process.cwd(), tempDir, relativePath); } else { targetPath = path.resolve(process.cwd(), filePath); } return fs.outputFile(targetPath, data); } function ensureDir2(dirPath) { const absPath = path.resolve(process.cwd(), dirPath); return fs.ensureDir(absPath); } function findFiles(pattern, options = {}) { return (0, import_fast_glob.default)(pattern, { dot: true, ...options, cwd: process.cwd() }); } function findTargetFiles(include, exclude = []) { return (0, import_fast_glob.default)(include, { ignore: exclude, dot: true, cwd: process.cwd() }); } function fileExists(filePath) { const absPath = path.resolve(process.cwd(), filePath); return fs.existsSync(absPath); } function readJsonSync2(filePath) { const absPath = path.resolve(process.cwd(), filePath); return fs.readJsonSync(absPath); } async function readJson(filePath, defaultValue) { try { const content = await readFile2(filePath, "utf-8"); return JSON.parse(content); } catch (error) { if (defaultValue !== void 0) { return defaultValue; } throw error; } } function writeJson(filePath, data, pretty = true) { const content = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data); return writeFile(filePath, content); } var fs, path, import_fast_glob; var init_fs = __esm({ "src/utils/fs.ts"() { "use strict"; fs = __toESM(require("fs-extra"), 1); path = __toESM(require("path"), 1); import_fast_glob = __toESM(require("fast-glob"), 1); } }); // src/utils/logger.ts var Logger; var init_logger = __esm({ "src/utils/logger.ts"() { "use strict"; init_config(); Logger = class { static getLogLevel() { var _a; try { const config = ConfigManager.get(); return ((_a = config.logging) == null ? void 0 : _a.level) ?? "normal"; } catch { return "normal"; } } static shouldLog(level) { const currentLevel = this.getLogLevel(); if (currentLevel === "minimal") { return level === "minimal"; } else if (currentLevel === "normal") { return level !== "verbose"; } else if (currentLevel === "verbose") { return true; } return false; } static success(message, level = "normal") { if (this.shouldLog(level)) { console.log(`\u2705 ${message}`); } } static info(message, level = "normal") { if (this.shouldLog(level)) { console.log(`\u2139\uFE0F ${message}`); } } static warn(message, level = "normal") { if (this.shouldLog(level)) { console.warn(`\u26A0\uFE0F ${message}`); } } static error(message, level = "normal") { if (this.shouldLog(level)) { console.error(`\u274C ${message}`); } } static verbose(message) { this.info(message, "verbose"); } }; } }); // src/config/index.ts function validateConfig(config) { var _a, _b, _c, _d; const errors = []; if (!config.include || !Array.isArray(config.include) || config.include.length === 0) { errors.push("include \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4"); } if (!config.outputDir || typeof config.outputDir !== "string") { errors.push("outputDir \u5B57\u6BB5\u5FC5\u987B\u662F\u6709\u6548\u7684\u5B57\u7B26\u4E32\u8DEF\u5F84"); } if (!config.locale || typeof config.locale !== "string") { errors.push("locale \u5B57\u6BB5\u5FC5\u987B\u662F\u6709\u6548\u7684\u8BED\u8A00\u4EE3\u7801"); } if ((_a = config.translation) == null ? void 0 : _a.enabled) { if (!config.translation.provider) { errors.push("\u542F\u7528\u7FFB\u8BD1\u65F6\u5FC5\u987B\u6307\u5B9A translation.provider"); } if (config.translation.provider === "baidu") { if (!((_b = config.translation.baidu) == null ? void 0 : _b.appid) || !((_c = config.translation.baidu) == null ? void 0 : _c.key)) { errors.push("\u4F7F\u7528\u767E\u5EA6\u7FFB\u8BD1\u65F6\u5FC5\u987B\u914D\u7F6E translation.baidu.appid \u548C translation.baidu.key"); } } } if (((_d = config.logging) == null ? void 0 : _d.level) && !["minimal", "normal", "verbose"].includes(config.logging.level)) { errors.push("logging.level \u5FC5\u987B\u662F minimal\u3001normal \u6216 verbose \u4E4B\u4E00"); } if (errors.length > 0) { Logger.error("\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25:", "minimal"); errors.forEach((error) => Logger.error(` - ${error}`, "minimal")); throw new Error(`\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25: ${errors.join("; ")}`); } } function loadConfig(customConfigPath) { let userConfig = {}; if (customConfigPath) { if (fileExists(customConfigPath)) { Logger.verbose(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6: ${customConfigPath}`); try { userConfig = readJsonSync2(customConfigPath); Logger.verbose("\u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u6210\u529F"); } catch (error) { throw new Error(`\u914D\u7F6E\u6587\u4EF6\u89E3\u6790\u5931\u8D25: ${error}`); } } else { Logger.warn(`\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ${customConfigPath}\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E`); } } const finalConfig = (0, import_lodash.merge)({}, defaultConfig, userConfig); validateConfig(finalConfig); Logger.verbose("\u914D\u7F6E\u9A8C\u8BC1\u901A\u8FC7"); return finalConfig; } var import_lodash, ConfigManagerClass, ConfigManager; var init_config = __esm({ "src/config/index.ts"() { "use strict"; import_lodash = require("lodash"); init_default_config(); init_fs(); init_logger(); ConfigManagerClass = class { config = null; init(config) { this.config = config; } get() { if (!this.config) { throw new Error("ConfigManager: config not initialized!"); } return this.config; } }; ConfigManager = new ConfigManagerClass(); } }); // src/translation/providers/baidu.ts var import_baidu_translate_service, BaiduTranslationProvider; var init_baidu = __esm({ "src/translation/providers/baidu.ts"() { "use strict"; init_logger(); import_baidu_translate_service = __toESM(require("baidu-translate-service"), 1); BaiduTranslationProvider = class { name = "baidu"; config; constructor(config) { this.config = config; Logger.verbose(`\u767E\u5EA6\u7FFB\u8BD1\u63D0\u4F9B\u8005\u521D\u59CB\u5316\u5B8C\u6210\uFF0Cappid: ${config.appid ? "\u5DF2\u914D\u7F6E" : "\u672A\u914D\u7F6E"}`); } async translate(text, from = "auto", to = "en") { if (!this.isConfigured()) { throw new Error("\u767E\u5EA6\u7FFB\u8BD1\u670D\u52A1\u672A\u914D\u7F6E\uFF0C\u8BF7\u8BBE\u7F6E appid \u548C key"); } try { const mappedFrom = this.mapLanguageCode(from); const mappedTo = this.mapLanguageCode(to); Logger.verbose(`\u53D1\u8D77\u767E\u5EA6\u7FFB\u8BD1\u8BF7\u6C42: ${mappedFrom} -> ${mappedTo}, \u6587\u672C\u957F\u5EA6: ${text.length}`); const response = await (0, import_baidu_translate_service.default)({ appid: this.config.appid, key: this.config.key, q: text, from: mappedFrom, to: mappedTo }); if (response.error_code) { throw new Error(`\u767E\u5EA6\u7FFB\u8BD1API\u9519\u8BEF: ${response.error_code} - ${response.error_msg}`); } if (!response.trans_result || response.trans_result.length === 0) { throw new Error("\u7FFB\u8BD1\u7ED3\u679C\u4E3A\u7A7A"); } const translatedText = response.trans_result.map((item) => item.dst).join("\n"); Logger.verbose(`\u7FFB\u8BD1\u6210\u529F: "${text}" -> "${translatedText}"`); return { originalText: text, translatedText, sourceLanguage: response.from, targetLanguage: response.to, provider: this.name }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(`\u767E\u5EA6\u7FFB\u8BD1\u5931\u8D25: ${errorMessage}`); throw error; } } isConfigured() { return !!(this.config.appid && this.config.key); } getSupportedLanguages() { return [ "auto", "zh", "en", "yue", "wyw", "jp", "kor", "fra", "spa", "th", "ara", "ru", "pt", "de", "it", "el", "nl", "pl", "bul", "est", "dan", "fin", "cs", "rom", "slo", "swe", "hu", "cht", "vie" ]; } /** * 映射语言代码到百度翻译API支持的格式 */ mapLanguageCode(lang) { const langMap = { "zh-CN": "zh", "zh-TW": "cht", "en-US": "en", ja: "jp", ko: "kor", fr: "fra", es: "spa", ar: "ara", ru: "ru", pt: "pt", de: "de", it: "it", nl: "nl", pl: "pl", sv: "swe", vi: "vie" }; return langMap[lang] ?? lang; } }; } }); // src/translation/queue.ts var TranslationQueue; var init_queue = __esm({ "src/translation/queue.ts"() { "use strict"; init_logger(); TranslationQueue = class { concurrency; tasks = []; completedResults = /* @__PURE__ */ new Map(); failedTasks = /* @__PURE__ */ new Map(); stats = { total: 0, pending: 0, completed: 0, failed: 0, inProgress: 0 }; batchDelay = 0; // 批次间延迟(毫秒) isApiLimited = false; // API限制状态标志 apiLimitResetTime = 0; // API限制重置时间 constructor(concurrency = 10) { this.concurrency = concurrency; } /** * 添加任务到队列 */ addTask(task) { task.currentRetry = 0; this.tasks.push(task); this.stats.total++; this.stats.pending++; } /** * 设置批次间延迟时间(毫秒) */ setBatchDelay(delay) { this.batchDelay = delay; } /** * 执行所有任务,返回结果映射 */ async executeAll() { Logger.info(`\u5F00\u59CB\u6267\u884C\u7FFB\u8BD1\u961F\u5217\uFF0C\u5E76\u53D1\u6570: ${this.concurrency}\uFF0C\u4EFB\u52A1\u603B\u6570: ${this.stats.total}`); this.completedResults.clear(); this.failedTasks.clear(); const workers = []; for (let i = 0; i < Math.min(this.concurrency, this.tasks.length); i++) { workers.push(this.worker()); } await Promise.all(workers); return this.completedResults; } /** * 工作线程,负责执行任务队列中的任务 */ async worker() { while (this.tasks.length > 0) { if (this.isApiLimited) { const now = Date.now(); if (now < this.apiLimitResetTime) { const waitTime = this.apiLimitResetTime - now; Logger.warn(`API\u901F\u7387\u9650\u5236\u4E2D\uFF0C\u7B49\u5F85 ${Math.ceil(waitTime / 1e3)} \u79D2\u540E\u7EE7\u7EED...`); await this.delay(waitTime); this.isApiLimited = false; } } const task = this.tasks.shift(); if (!task) continue; this.stats.pending--; this.stats.inProgress++; try { const result = await task.execute(); this.completedResults.set(task.id, result); this.stats.completed++; this.stats.inProgress--; Logger.verbose(`\u4EFB\u52A1 ${task.id} \u6267\u884C\u6210\u529F`); if (this.batchDelay > 0) { await this.delay(this.batchDelay); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (this.isApiLimitError(errorMessage)) { this.handleApiLimitError(); this.tasks.unshift(task); this.stats.pending++; } else { Logger.error(`\u4EFB\u52A1 ${task.id} \u6267\u884C\u5931\u8D25: ${errorMessage}`); if ((task.currentRetry ?? 0) < task.maxRetries) { task.currentRetry = (task.currentRetry ?? 0) + 1; Logger.warn( `\u4EFB\u52A1 ${task.id} \u6267\u884C\u5931\u8D25\uFF0C\u51C6\u5907\u7B2C ${task.currentRetry} \u6B21\u91CD\u8BD5: ${errorMessage}` ); await this.delay(task.retryDelay); this.tasks.push(task); this.stats.pending++; } else { const finalError = error instanceof Error ? error : new Error(String(error)); this.failedTasks.set(task.id, finalError); this.stats.failed++; } } this.stats.inProgress--; } } } /** * 检测是否为API限制错误 */ isApiLimitError(errorMessage) { return errorMessage.includes("API\u9519\u8BEF: 54003") || errorMessage.includes("Invalid Access Limit") || errorMessage.includes("rate limit") || errorMessage.includes("too many requests"); } /** * 处理API限制错误 */ handleApiLimitError() { this.isApiLimited = true; const cooldownTime = 60 * 1e3; this.apiLimitResetTime = Date.now() + cooldownTime; Logger.warn(`\u68C0\u6D4B\u5230API\u901F\u7387\u9650\u5236\uFF0C\u5C06\u6682\u505C ${cooldownTime / 1e3} \u79D2\u540E\u7EE7\u7EED`); } /** * 获取已完成任务的结果 */ getCompletedResults() { return this.completedResults; } /** * 获取失败任务的错误信息 */ getFailedTasks() { return this.failedTasks; } /** * 获取队列统计信息 */ getStats() { return { ...this.stats }; } /** * Promise延迟等待 */ delay(ms) { return new Promise((resolve2) => setTimeout(resolve2, ms)); } }; } }); // src/translation/cache.ts var TranslationCache; var init_cache = __esm({ "src/translation/cache.ts"() { "use strict"; init_logger(); TranslationCache = class _TranslationCache { static instance; cache = /* @__PURE__ */ new Map(); constructor() { } /** * 获取翻译缓存管理器实例 */ static getInstance() { if (!_TranslationCache.instance) { _TranslationCache.instance = new _TranslationCache(); Logger.verbose("\u521D\u59CB\u5316\u7FFB\u8BD1\u5185\u5B58\u7F13\u5B58"); } return _TranslationCache.instance; } /** * 从缓存中获取翻译结果 */ get(text, from, to, provider) { const key = this.generateCacheKey(text, from, to, provider); const cached = this.cache.get(key); if (cached) { Logger.verbose(`\u7F13\u5B58\u547D\u4E2D: "${text}" (${from} -> ${to})`); return cached; } return null; } /** * 将翻译结果存入缓存 */ set(text, translatedText, from, to, provider) { const key = this.generateCacheKey(text, from, to, provider); this.cache.set(key, { originalText: text, translatedText, sourceLanguage: from, targetLanguage: to, provider, timestamp: Date.now() }); } /** * 清空缓存 */ clear() { this.cache.clear(); Logger.verbose("\u7FFB\u8BD1\u7F13\u5B58\u5DF2\u6E05\u7A7A"); } /** * 获取缓存大小 */ size() { return this.cache.size; } /** * 生成缓存键 */ generateCacheKey(text, from, to, provider) { return `${provider}:${from}:${to}:${text}`; } }; } }); // src/translation/manager.ts var path3, TranslationManager; var init_manager = __esm({ "src/translation/manager.ts"() { "use strict"; init_baidu(); init_logger(); init_queue(); init_fs(); init_cache(); path3 = __toESM(require("path"), 1); TranslationManager = class { providers = /* @__PURE__ */ new Map(); config; cache; constructor(config) { this.config = config; Logger.verbose(`\u521D\u59CB\u5316\u7FFB\u8BD1\u7BA1\u7406\u5668\uFF0C\u63D0\u4F9B\u8005: ${config.provider}\uFF0C\u5E76\u53D1\u6570: ${config.concurrency}`); this.cache = TranslationCache.getInstance(); this.initializeProviders(); } initializeProviders() { var _a, _b; if (((_a = this.config.baidu) == null ? void 0 : _a.appid) && ((_b = this.config.baidu) == null ? void 0 : _b.key)) { const baiduProvider = new BaiduTranslationProvider({ appid: this.config.baidu.appid, key: this.config.baidu.key }); this.providers.set("baidu", baiduProvider); Logger.verbose("\u767E\u5EA6\u7FFB\u8BD1\u670D\u52A1\u5DF2\u521D\u59CB\u5316"); } } /** * 翻译文本 */ async translate(text, from = this.config.defaultSourceLang ?? "auto", to = this.config.defaultTargetLang ?? "en") { if (!this.config.enabled) { throw new Error("\u7FFB\u8BD1\u670D\u52A1\u672A\u542F\u7528"); } const provider = this.providers.get(this.config.provider); if (!provider) { throw new Error(`\u7FFB\u8BD1\u670D\u52A1\u63D0\u4F9B\u8005 '${this.config.provider}' \u672A\u627E\u5230\u6216\u672A\u914D\u7F6E`); } if (!provider.isConfigured()) { throw new Error(`\u7FFB\u8BD1\u670D\u52A1\u63D0\u4F9B\u8005 '${this.config.provider}' \u914D\u7F6E\u4E0D\u5B8C\u6574`); } const providerName = provider.name ?? this.config.provider; const cachedResult = this.cache.get(text, from, to, providerName); if (cachedResult) { Logger.info(`[\u7F13\u5B58] \u7FFB\u8BD1: "${text}" -> "${cachedResult.translatedText}"`); return { originalText: cachedResult.originalText, translatedText: cachedResult.translatedText, sourceLanguage: cachedResult.sourceLanguage, targetLanguage: cachedResult.targetLanguage, provider: cachedResult.provider }; } Logger.verbose(`\u4F7F\u7528 ${providerName} \u7FFB\u8BD1: "${text}" (${from} -> ${to})`); try { const result = await provider.translate(text, from, to); Logger.info(`\u7FFB\u8BD1\u5B8C\u6210: "${text}" -> "${result.translatedText}"`); this.cache.set(text, result.translatedText, from, to, providerName); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(`\u7FFB\u8BD1\u5931\u8D25: ${errorMessage}`); throw error; } } /** * 批量翻译文本数组 */ async translateBatch(texts, from = this.config.defaultSourceLang ?? "auto", to = this.config.defaultTargetLang ?? "en") { if (!this.config.enabled) { throw new Error("\u7FFB\u8BD1\u670D\u52A1\u672A\u542F\u7528"); } const concurrency = Math.min(this.config.concurrency ?? 5, 5); const retryTimes = this.config.retryTimes ?? 3; const retryDelay = Math.max(this.config.retryDelay ?? 1e3, 1e3); const batchDelay = Math.max(this.config.batchDelay ?? 500, 500); Logger.info( `\u5F00\u59CB\u6279\u91CF\u7FFB\u8BD1\uFF0C\u6587\u672C\u6570\u91CF: ${texts.length}\uFF0C\u5E76\u53D1\u6570: ${concurrency}\uFF0C\u91CD\u8BD5\u6B21\u6570: ${retryTimes}`, "normal" ); Logger.verbose(`\u7FFB\u8BD1\u65B9\u5411: ${from} -> ${to}`); const providerName = this.config.provider; const textsToTranslate = []; const cachedResults = /* @__PURE__ */ new Map(); for (let i = 0; i < texts.length; i++) { const text = texts[i]; if (!text) continue; const cachedResult = this.cache.get(text, from || "auto", to || "en", providerName); if (cachedResult) { Logger.verbose(`[\u7F13\u5B58] \u6587\u672C ${i + 1}/${texts.length}: "${text}"`); cachedResults.set(`translate_${i}`, { originalText: cachedResult.originalText, translatedText: cachedResult.translatedText, sourceLanguage: cachedResult.sourceLanguage, targetLanguage: cachedResult.targetLanguage, provider: cachedResult.provider }); } else { textsToTranslate.push(text); } } const queue = new TranslationQueue(concurrency); queue.setBatchDelay(batchDelay); for (let i = 0; i < texts.length; i++) { if (!cachedResults.has(`translate_${i}`)) { const text = texts[i]; if (!text) continue; queue.addTask({ id: `translate_${i}`, execute: () => this.translate(text, from || "auto", to || "en"), maxRetries: retryTimes, retryDelay }); } } Logger.info(`\u9700\u8981\u7FFB\u8BD1\u7684\u6587\u672C: ${textsToTranslate.length}\uFF0C\u4ECE\u7F13\u5B58\u52A0\u8F7D: ${cachedResults.size}`); if (textsToTranslate.length === 0) { Logger.info(`\u6240\u6709\u6587\u672C\u90FD\u4ECE\u7F13\u5B58\u52A0\u8F7D\uFF0C\u8DF3\u8FC7API\u8C03\u7528`); const results2 = []; for (let i = 0; i < texts.length; i++) { const result = cachedResults.get(`translate_${i}`); if (result) { results2.push(result); } } return results2; } const completedResults = await queue.executeAll(); const results = []; const failedTasks = queue.getFailedTasks(); for (let i = 0; i < texts.length; i++) { const taskId = `translate_${i}`; if (cachedResults.has(taskId)) { const result2 = cachedResults.get(taskId); if (result2) { results.push(result2); } continue; } const result = completedResults.get(taskId); if (result) { results.push(result); } else { const error = failedTasks.get(taskId); const errorMessage = (error == null ? void 0 : error.message) ?? "\u672A\u77E5\u9519\u8BEF"; const currentText = texts[i]; if (currentText) { Logger.error(`\u6587\u672C "${currentText}" \u7FFB\u8BD1\u5931\u8D25: ${errorMessage}`); results.push({ originalText: currentText, translatedText: currentText, // 失败时返回原文 sourceLanguage: from || "auto", targetLanguage: to || "en", provider: this.config.provider }); } } } const stats = queue.getStats(); Logger.info( `\u6279\u91CF\u7FFB\u8BD1\u5B8C\u6210\uFF0C\u6210\u529F: ${stats.completed}\uFF0C\u5931\u8D25: ${stats.failed}\uFF0C\u603B\u8BA1: ${texts.length}\uFF0C\u4F7F\u7528\u7F13\u5B58: ${cachedResults.size}` ); return results; } /** * 翻译语言文件(JSON) * 此方法整合了原来的translateJsonFile和translateLanguageFiles * 支持增量翻译和实时写入结果 */ async translateLanguageFile(sourcePath, targetLocale, from = this.config.defaultSourceLang ?? "auto", to = this.config.defaultTargetLang ?? "en", incrementalMode = true) { if (!fileExists(sourcePath)) { throw new Error(`\u6E90\u8BED\u8A00\u6587\u4EF6\u4E0D\u5B58\u5728: ${sourcePath}`); } Logger.info(`\u{1F4D6} \u8BFB\u53D6JSON\u6587\u4EF6: ${sourcePath}`); const sourceContent = await readJson(sourcePath); const totalSourceItems = Object.keys(sourceContent).length; const outputPath = path3.join(path3.dirname(sourcePath), `${targetLocale}.json`); let existingTranslations = {}; let skippedCount = 0; if (incrementalMode && fileExists(outputPath)) { Logger.info(`\u589E\u91CF\u7FFB\u8BD1\u6A21\u5F0F: \u52A0\u8F7D\u5DF2\u6709\u7684\u7FFB\u8BD1\u6587\u4EF6 ${outputPath}`); try { existingTranslations = await readJson(outputPath); Logger.info(`\u5DF2\u52A0\u8F7D ${Object.keys(existingTranslations).length} \u4E2A\u5DF2\u7FFB\u8BD1\u7684\u9879`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.warn(`\u8BFB\u53D6\u5DF2\u6709\u7FFB\u8BD1\u6587\u4EF6\u5931\u8D25: ${errorMessage}\uFF0C\u5C06\u521B\u5EFA\u65B0\u6587\u4EF6`); existingTranslations = {}; } } const keysToTranslate = []; const textsToTranslate = []; const finalTranslations = { ...existingTranslations }; for (const key in sourceContent) { const value = sourceContent[key]; if (typeof value === "string") { if (incrementalMode && key in existingTranslations && existingTranslations[key]) { Logger.verbose(`\u8DF3\u8FC7\u5DF2\u7FFB\u8BD1\u7684\u952E: ${key}`); skippedCount++; continue; } keysToTranslate.push(key); textsToTranslate.push(value); } else { finalTranslations[key] = value; } } const needTranslateCount = textsToTranslate.length; if (needTranslateCount === 0) { Logger.info(`\u6CA1\u6709\u9700\u8981\u7FFB\u8BD1\u7684\u65B0\u6587\u672C\uFF0C\u4FDD\u7559\u6240\u6709\u5DF2\u7FFB\u8BD1\u5185\u5BB9`); await writeJson(outputPath, finalTranslations, true); return { outputPath, totalCount: totalSourceItems, successCount: 0, // 没有新翻译,成功数为0 skippedCount // 返回跳过的数量 }; } Logger.info(`\u{1F504} \u5F00\u59CB\u7FFB\u8BD1 ${needTranslateCount} \u4E2A\u6587\u672C\u6761\u76EE...`); const results = await this.translateBatch(textsToTranslate, from, to); let successCount = 0; const realTimeWriteInterval = 50; for (let i = 0; i < results.length; i++) { const key = keysToTranslate[i]; const result = results[i]; if (key && typeof key === "string" && result && result.translatedText !== result.originalText) { finalTranslations[key] = result.translatedText; successCount++; } else if (key && typeof key === "string") { finalTranslations[key] = sourceContent[key]; } if ((i + 1) % realTimeWriteInterval === 0 || i === results.length - 1) { try { await writeJson(outputPath, finalTranslations, true); Logger.verbose(`\u5B9E\u65F6\u4FDD\u5B58\u7FFB\u8BD1\u7ED3\u679C\u5230 ${outputPath}\uFF0C\u5DF2\u5904\u7406 ${i + 1}/${results.length}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.warn(`\u5B9E\u65F6\u4FDD\u5B58\u7FFB\u8BD1\u7ED3\u679C\u5931\u8D25: ${errorMessage}`); } } } await writeJson(outputPath, finalTranslations, true); Logger.verbose(`\u7FFB\u8BD1\u5B8C\u6210\uFF0C\u7ED3\u679C\u4FDD\u5B58\u5230: ${outputPath}`); return { outputPath, totalCount: totalSourceItems, successCount, skippedCount }; } /** * 检查服务是否可用 */ isAvailable() { if (!this.config.enabled) { return false; } const provider = this.providers.get(this.config.provider); return provider ? provider.isConfigured() : false; } /** * 获取当前提供者支持的语言 */ getSupportedLanguages() { const provider = this.providers.get(this.config.provider); return provider ? provider.getSupportedLanguages() : []; } /** * 获取可用的翻译服务提供者列表 */ getAvailableProviders() { return Array.from(this.providers.keys()).filter((name) => { const provider = this.providers.get(name); return (provider == null ? void 0 : provider.isConfigured()) ?? false; }); } /** * 获取缓存状态 */ getCacheStatus() { return { size: this.cache.size() }; } /** * 清除缓存 */ clearCache() { this.cache.clear(); Logger.info("\u7FFB\u8BD1\u7F13\u5B58\u5DF2\u6E05\u7A7A"); } }; } }); // src/translation/cli.ts var cli_exports = {}; __export(cli_exports, { translateCommand: () => translateCommand }); async function translateCommand(options) { var _a, _b, _c, _d, _e; const config = loadConfig(options.config); ConfigManager.init(config); if (!((_a = config.translation) == null ? void 0 : _a.enabled)) { Logger.info("\u7FFB\u8BD1\u529F\u80FD\u672A\u542F\u7528\uFF0C\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E translation.enabled = true", "normal"); return; } const translationManager = new TranslationManager({ enabled: config.translation.enabled, provider: config.translation.provider ?? "baidu", defaultSourceLang: config.translation.defaultSourceLang ?? "zh", defaultTargetLang: config.translation.defaultTargetLang ?? "en", concurrency: config.translation.concurrency ?? 5, retryTimes: config.translation.retryTimes ?? 3, retryDelay: config.translation.retryDelay ?? 1e3, batchDelay: config.translation.batchDelay ?? 500, baidu: ((_b = config.translation.baidu) == null ? void 0 : _b.appid) && ((_c = config.translation.baidu) == null ? void 0 : _c.key) ? { appid: config.translation.baidu.appid, key: config.translation.baidu.key } : void 0, custom: ((_d = config.translation.custom) == null ? void 0 : _d.endpoint) && ((_e = config.translation.custom) == null ? void 0 : _e.apiKey) ? { endpoint: config.translation.custom.endpoint, apiKey: config.translation.custom.apiKey } : void 0 }); if (!translationManager.isAvailable()) { Logger.error("\u7FFB\u8BD1\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E", "minimal"); Logger.info("\u767E\u5EA6\u7FFB\u8BD1\u9700\u8981\u914D\u7F6E appid \u548C key", "normal"); return; } const defaultSourceLang = config.translation.defaultSourceLang ?? "zh"; const defaultTargetLang = config.translation.defaultTargetLang ?? config.fallbackLocale ?? "en"; const from = options.from ?? defaultSourceLang; const to = options.to ?? defaultTargetLang; const incrementalMode = options.incremental !== false; try { if (options.test && options.input) { await handleTranslateTest(translationManager, options.input, from, to); } else if (options.json) { await handleTranslateJsonFile(translationManager, options.json, from, to, incrementalMode); } else if (options.batch) { await handleTranslateBatchFiles(translationManager, from, to, incrementalMode); } else if (options.input) { await handleTranslateInput(translationManager, options.input, from, to); } else { const outputDir = config.outputDir ?? "locales"; const sourceLocale = config.locale ?? "zh-CN"; const targetLocale = config.fallbackLocale ?? "en-US"; Logger.info( `\u672A\u6307\u5B9A\u7FFB\u8BD1\u5185\u5BB9\uFF0C\u5C06\u4ECE ${outputDir} \u76EE\u5F55\u8BFB\u53D6 ${sourceLocale}.json \u6587\u4EF6\u5E76\u7FFB\u8BD1\u6210 ${targetLocale}`, "normal" ); const sourceLang = sourceLocale.split("-")[0] || "zh"; const targetLang = targetLocale.split("-")[0] || "en"; try { const sourcePath = path4.join(outputDir, `${sourceLocale}.json`); if (!fileExists(sourcePath)) { throw new Error(`\u6E90\u8BED\u8A00\u6587\u4EF6\u4E0D\u5B58\u5728: ${sourcePath}\uFF0C\u8BF7\u5148\u8FD0\u884C\u751F\u6210\u547D\u4EE4\u521B\u5EFA\u6E90\u8BED\u8A00\u6587\u4EF6`); } Logger.info(`\u{1F4D6} \u4ECE\u6E90\u8BED\u8A00\u6587\u4EF6\u8BFB\u53D6: ${sourcePath}`); const { outputPath, totalCount, successCount, skippedCount } = await translationManager.translateLanguageFile( sourcePath, targetLocale, sourceLang, targetLang, incrementalMode ); Logger.success(`\u2705 \u7FFB\u8BD1\u5B8C\u6210\uFF0C\u7ED3\u679C\u4FDD\u5B58\u5230: ${outputPath}`, "normal"); if (skippedCount > 0) { if (successCount > 0) { Logger.info( `\u{1F4CA} \u6210\u529F\u7FFB\u8BD1: ${successCount}\u9879\u65B0\u5185\u5BB9\uFF0C\u8DF3\u8FC7\u5DF2\u7FFB\u8BD1\u9879: ${skippedCount}\u9879\uFF0C\u5171${totalCount}\u9879`, "normal" ); } else { Logger.info( `\u{1F4CA} \u65E0\u65B0\u5185\u5BB9\u9700\u8981\u7FFB\u8BD1\uFF0C\u5DF2\u6709\u7FFB\u8BD1\u9879: ${skippedCount}\u9879\uFF0C\u5171${totalCount}\u9879`, "normal" ); } } else { Logger.info(`\u{1F4CA} \u6210\u529F\u7FFB\u8BD1: ${successCount}/${totalCount}\u9879`, "normal"); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(`\u7FFB\u8BD1\u5931\u8D25: ${errorMessage}`, "minimal"); showUsageHelp(); } } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(`\u7FFB\u8BD1\u5931\u8D25: ${errorMessage}`, "minimal"); process.exit(1); } } async function handleTranslateTest(manager, text, from, to) { Logger.info(`\u6D4B\u8BD5\u7FFB\u8BD1\u6A21\u5F0F (${from} -> ${to})`, "normal"); Logger.info(`\u539F\u6587: ${text}`, "normal"); const result = await manager.translate(text, from, to); Logger.success(`\u8BD1\u6587: ${result.translatedText}`, "normal"); Logger.info(`\u63D0\u4F9B\u8005: ${result.provider}`, "normal"); } async function handleTranslateJsonFile(manager, jsonPath, from, to, incremental = true) { const targetLocale = ConfigManager.get().fallbackLocale || "en-US"; const { outputPath, totalCount, successCount, skippedCount } = await manager.translateLanguageFile(jsonPath, targetLocale, from, to, incremental); Logger.success(`\u2705 \u7FFB\u8BD1\u5B8C\u6210\uFF0C\u7ED3\u679C\u4FDD\u5B58\u5230: ${outputPath}`, "normal"); if (skippedCount > 0) { if (successCount > 0) { Logger.info( `\u{1F4CA} \u6210\u529F\u7FFB\u8BD1: ${successCount}\u9879\u65B0\u5185\u5BB9\uFF0C\u8DF3\u8FC7\u5DF2\u7FFB\u8BD1\u9879: ${skippedCount}\u9879\uFF0C\u5171${totalCount}\u9879`, "normal" ); } else { Logger.info( `\u{1F4CA} \u65E0\u65B0\u5185\u5BB9\u9700\u8981\u7FFB\u8BD1\uFF0C\u5DF2\u6709\u7FFB\u8BD1\u9879: ${skippedCount}\u9879\uFF0C\u5171${totalCount}\u9879`, "normal" ); } } else { Logger.info(`\u{1F4CA} \u6210\u529F\u7FFB\u8BD1: ${successCount}/${totalCount}\u9879`, "normal"); } } async function handleTranslateBatchFiles(manager, from, to, incremental = true) { const config = ConfigManager.get(); const outputDir = config.outputDir ?? "./locales"; const sourceLocale = config.locale ?? from; const targetLocale = config.fallbackLocale ?? "en-US"; const sourcePath = path4.join(outputDir, `${sourceLocale}.json`); if (!fileExists(sourcePath)) { throw new Error(`\u6E90\u8BED\u8A00\u6587\u4EF6\u4E0D\u5B58\u5728: ${sourcePath}\uFF0C\u8BF7\u5148\u8FD0\u884C\u751F\u6210\u547D\u4EE4\u521B\u5EFA\u6E90\u8BED\u8A00\u6587\u4EF6`); } Logger.info(`\u{1F4D6} \u4ECE\u6E90\u8BED\u8A00\u6587\u4EF6\u8BFB\u53D6: ${sourcePath}`); const { outputPath, totalCount, successCount, skippedCount } = await manager.translateLanguageFile(sourcePath, targetLocale, from, to, incremental); Logger.success(`\u2705 \u6279\u91CF\u7FFB\u8BD1\u5B8C\u6210\uFF0C\u7ED3\u679C\u4FDD\u5B58\u5230: ${outputPath}`, "normal"); if (skippedCount > 0) { if (successCount > 0) { Logger.info( `\u{1F4CA} \u6210\u529F\u7FFB\u8BD1: ${successCount}\u9879\u65B0\u5185\u5BB9\uFF0C\u8DF3\u8FC7\u5DF2\u7FFB\u8BD1\u9879: ${skippedCount}\u9879\uFF0C\u5171${totalCount}\u9879`, "normal" ); } else { Logger.info( `\u{1F4CA} \u65E0\u65B0\u5185\u5BB9\u9700\u8981\u7FFB\u8BD1\uFF0C\u5DF2\u6709\u7FFB\u8BD1\u9879: ${skippedCount}\u9879\uFF0C\u5171${totalCount}\u9879`, "normal" ); } } else { Logger.info(`\u{1F4CA} \u6210\u529F\u7FFB\u8BD1: ${successCount}/${totalCount}\u9879`, "normal"); } } async function handleTranslateInput(manager, input, from, to) { let text = input; if (fileExists(input)) { try { text = await readFile2(input, "utf-8"); Logger.info(`\u4ECE\u6587\u4EF6\u8BFB\u53D6\u5185\u5BB9: ${input}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25: ${errorMessage}`); } } Logger.info(`\u6B63\u5728\u7FFB\u8BD1 (${from} -> ${to})...`, "normal"); const result = await manager.translate(text, from, to); Logger.info("\u7FFB\u8BD1\u7ED3\u679C:", "normal"); Logger.info(`\u539F\u6587 (${result.sourceLanguage}): ${result.originalText}`, "normal"); Logger.success(`\u8BD1\u6587 (${result.targetLanguage}): ${result.translatedText}`, "normal"); Logger.info(`\u63D0\u4F9B\u8005: ${result.provider}`, "verbose"); } function showUsageHelp() { Logger.error("\u8BF7\u6307\u5B9A\u7FFB\u8BD1\u5185\u5BB9\uFF1A", "minimal"); Logger.info(" \u4F7F\u7528 -i \u6307\u5B9A\u6587\u672C\u6216\u6587\u4EF6\u8DEF\u5F84", "normal"); Logger.info(" \u4F7F\u7528 -j \u6307\u5B9AJSON\u6587\u4EF6\u8DEF\u5F84", "normal"); Logger.info(" \u4F7F\u7528 --batch \u6279\u91CF\u7FFB\u8BD1\u8BED\u8A00\u6587\u4EF6", "normal"); Logger.info(' \u4F7F\u7528 --test -i "\u6587\u672C" \u6D4B\u8BD5\u7FFB\u8BD1', "normal"); Logger.info(" \u4F7F\u7528 --incremental=false \u7981\u7528\u589E\u91CF\u7FFB\u8BD1\u6A21\u5F0F", "normal"); } var path4; var init_cli = __esm({ "src/translation/cli.ts"() { "use strict"; init_config(); init_manager(); init_fs(); init_logger(); path4 = __toESM(require("path"), 1); } }); // src/index.ts var index_exports = {}; __export(index_exports, { ConfigManager: () => ConfigManager, createI18nKey: () => createI18nKey, ensureDir: () => ensureDir2, fileExists: () => fileExists, findFiles: () => findFiles, findTargetFiles: () => findTargetFiles, flushI18nCache: () => flushI18nCache, initI18nCache: () => initI18nCache, loadConfig: () => loadConfig, readFile: () => readFile2, readJson: () => readJson, readJsonSync: () => readJsonSync2, scanAndReplaceAll: () => scanAndReplaceAll, writeFile: () => writeFile, writeFileWithTempDir: () => writeFileWithTempDir, writeJson: () => writeJson }); module.exports = __toCommonJS(index_exports); // src/cli.ts var import_commander = require("commander"); init_config(); // src/ast/index.ts var import_parser2 = require("@babel/parser"); var t2 = __toESM(require("@babel/types"), 1); init_fs(); init_config(); // src/gen-key-value.ts init_fs(); var import_pinyin_pro = require("pinyin-pro"); var path2 = __toESM(require("path"), 1); init_config(); var import_string_hash = __toESM(require("string-hash"), 1); init_logger(); var keyValueCache = {}; var valueKeyCache = {}; var outputFilePath = ""; async function initI18nCache() { var _a; const config = ConfigManager.get(); const outputDir = config.outputDir ?? "locales"; await ensureDir2(outputDir); const localeFileName = ((_a = config.output) == null ? void 0 : _a.localeFileName) ?? "{locale}.json"; const fileName = localeFileName.replace("{locale}", config.locale ?? "zh-CN"); outputFilePath = path2.join(outputDir, fileName); keyValueCache = await readJson(outputFilePath, {}); valueKeyCache = {}; for (const [key, value] of Object.entries(keyValueCache)) { valueKeyCache[value] = key; } const existingKeyCount = Object.keys(keyValueCache).length; if (existingKeyCount > 0) { Logger.verbose(`\u52A0\u8F7D\u4E86 ${existingKeyCount} \u4E2A\u5DF2\u5B58\u5728\u7684\u7FFB\u8BD1\u952E`); } await writeJson(outputFilePath, keyValueCache); } function toShortHash(text) { var _a; const config = ConfigManager.get(); const hashLength = ((_a = config.keyGeneration) == null ? void 0 : _a.hashLength) ?? 6; return (0, import_string_hash.default)(text).toString(36).slice(0, hashLength); } function generateUniqueKey(baseKey, text) { var _a, _b; const config = ConfigManager.get(); const separator = ((_a = config.keyGeneration) == null ? void 0 : _a.separator) ?? "_"; const maxRetry = ((_b = config.keyGeneration) == null ? void 0 : _b.maxRetryCount) ?? 5; if (!keyValueCache[baseKey]) { return baseKey; } let finalKey = baseKey + separator + toShortHash(text); let tryCount = 0; while (keyValueCache[finalKey] && tryCount < maxRetry) { finalKey = baseKey + separator + toShortHash(text + Math.random().toString()); tryCount++; } if (tryCount >= maxRetry) { Logger.warn(`\u751F\u6210\u552F\u4E00key\u5931\u8D25\uFF0C\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570: ${baseKey}`); finalKey = baseKey + separator + Date.now().toString(36); } return finalKey; } function createI18nKey(text) { var _a, _b, _c, _d, _e, _f; const config = ConfigManager.get(); const reuseExistingKey = ((_a = config.keyGeneration) == null ? void 0 : _a.reuseExistingKey) ?? true; if (reuseExistingKey && valueKeyCache[text]) { Logger.verbose(`\u91CD\u590D\u4F7F\u7528\u5DF2\u5B58\u5728\u6587\u6848\u7684key: "${valueKeyCache[text]}" for "${text}"`); return valueKeyCache[text]; } const maxLength = ((_b = config.keyGeneration) == null ? void 0 : _b.maxChineseLength) ?? 10; const han = (((_c = text.match(/[\u4e00-\u9fa5]+/g)) == null ? void 0 : _c.join("")) ?? "").slice(0, maxLength); if (!han) { return ""; } const pinyinOptions = ((_d = config.keyGeneration) == null ? void 0 : _d.pinyinOptions) ?? { toneType: "none", type: "array" }; const separator = ((_e = config.keyGeneration) == null ? void 0 : _e.separator) ?? "_"; const keyPrefix = ((_f = config.keyGeneration) == null ? void 0 : _f.keyPrefix) ?? ""; const baseKey = ((0, import_pinyin_pro.pinyin)(han, { toneType: pinyinOptions.toneType ?? "none", type: "array" }) ?? []).join(separator); if (!baseKey) { return ""; } const keyWithPrefix = keyPrefix ? `${keyPrefix}${separator}${baseKey}` : baseKey; const finalKey = generateUniqueKey(keyWithPrefix, text); keyValueCache[finalKey] = text; valueKeyCache[text] = finalKey; return finalKey; } async function flushI18nCache() { var _a; if (outputFilePath) { const config = ConfigManager.get(); const prettyJson = ((_a = config.output) == null ? void 0 : _a.prettyJson) ?? true; await writeJson(outputFilePath, keyValueCache, prettyJson); const keyCount = Object.keys(keyValueCache).length; Logger.info(`\u5DF2\u4FDD\u5B58 ${keyCount} \u4E2A\u7FFB\u8BD1\u952E\u5230 ${outputFilePath}`, "normal"); } } // src/ast/index.ts init_logger(); // src/utils/import-manager.ts var import_parser = require("@babel/parser"); var t = __toESM(require("@babel/types"), 1); init_logger(); // src/utils/pattern.ts init_logger(); var import_micromatch = __toESM(require("micromatch"), 1); function matchPattern(pattern, filePath) { try { return import_micromatch.default.isMatch(filePath, pattern); } catch (error) { Logger.warn(`\u6A21\u5F0F\u5339\u914D\u51FA\u9519 - pattern: ${pattern}, filePath: ${filePath}, error: ${error}`); return false; } } function findMatchingImport(filePath, imports = {}) { var _a; Logger.verbose(`findMatchingImport: ${filePath}`); const patterns = Object.keys(imports).sort((a, b) => { const scoreA = getPatternSpecificity(a); const scoreB = getPatternSpecificity(b); return scoreB - scoreA; }); for (const pattern of patterns) { if (matchPattern(pattern, filePath)) { Logger.verbose(`\u5339\u914D\u5230\u6A21\u5F0F: ${pattern} -> ${filePath}`); return ((_a = imports[pattern]) == null ? void 0 : _a.importStatement) || null; } } Logger.verbose(`\u672A\u627E\u5230\u5339\u914D\u7684import\u914D\u7F6E: ${filePath}`); return null; } function getPatternSpecificity(pattern) { var _a, _b, _c; let score = 0; if (!pattern.includes("*")) { score += 100; } if (pattern.includes(".{") || pattern.match(/\.\w+$/)) { score += 50; } score += (((_a = pattern.match(/\//g)) == null ? void 0 : _a.length) || 0) * 10; score -= (((_b = pattern.match(/\*\*/g)) == null ? void 0 : _b.length) || 0) * 20; score -= (((_c = pattern.match(/(?<!\*)\*(?!\*)/g)) == null ? void 0 : _c.length) || 0) * 5; return score; } // src/utils/import-manager.ts var generate = require("@babel/generator").default; function hasExistingImport(ast, importStatement) { var _a; try { const importAst = (0, import_parser.parse)(importStatement, { sourceType: "module", plugins: ["jsx", "typescript"] }); if (!((_