td-web-cli 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/interface.d.ts +6 -0
- package/dist/api/interface.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/modules/i18n/excel2json/index.d.ts +9 -0
- package/dist/modules/i18n/excel2json/index.d.ts.map +1 -0
- package/dist/modules/i18n/excel2json/index.js +119 -18
- package/dist/modules/i18n/extractEntry/index.d.ts +2 -0
- package/dist/modules/i18n/extractEntry/index.d.ts.map +1 -0
- package/dist/modules/i18n/index.d.ts +8 -0
- package/dist/modules/i18n/index.d.ts.map +1 -0
- package/dist/modules/i18n/json2excel/index.d.ts +2 -0
- package/dist/modules/i18n/json2excel/index.d.ts.map +1 -0
- package/dist/modules/i18n/jsonMerge/index.d.ts +2 -0
- package/dist/modules/i18n/jsonMerge/index.d.ts.map +1 -0
- package/dist/utils/index.d.ts +151 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +39 -24
- package/package.json +4 -1
- package/.prettierignore +0 -2
- package/.prettierrc +0 -7
- package/setting.json +0 -47
- package/src/api/index.ts +0 -188
- package/src/api/interface.ts +0 -6
- package/src/index.ts +0 -78
- package/src/modules/i18n/excel2json/index.ts +0 -385
- package/src/modules/i18n/extractEntry/index.ts +0 -3
- package/src/modules/i18n/index.ts +0 -78
- package/src/modules/i18n/json2excel/index.ts +0 -3
- package/src/modules/i18n/jsonMerge/index.ts +0 -3
- package/src/utils/index.ts +0 -352
- package/tsconfig.json +0 -12
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const getData: <T>(url: string, params?: Record<string, unknown>, headers?: Record<string, string>) => Promise<T>;
|
|
2
|
+
export declare const postData: <T, R>(url: string, params: T, headers?: Record<string, string>) => Promise<R>;
|
|
3
|
+
export declare const postStream: <T>(url: string, params: T, headers: Record<string, string> | undefined, onData: (chunk: string) => void, onError?: (error: Error) => void, onComplete?: () => void, signal?: AbortSignal) => Promise<void>;
|
|
4
|
+
export declare const postSSE: <T>(url: string, params: T, headers: Record<string, string> | undefined, onMessage: (event: string, data: string) => void, onError?: (error: Error) => void, signal?: AbortSignal) => Promise<void>;
|
|
5
|
+
export declare const putData: <T, R>(url: string, params: T, headers?: Record<string, string>) => Promise<R>;
|
|
6
|
+
export declare const deleteData: <T>(url: string, params?: Record<string, unknown>, headers?: Record<string, string>) => Promise<T>;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,OAAO,GAAU,CAAC,EAC7B,KAAK,MAAM,EACX,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,UAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KACnC,OAAO,CAAC,CAAC,CAGX,CAAC;AAGF,eAAO,MAAM,QAAQ,GAAU,CAAC,EAAE,CAAC,EACjC,KAAK,MAAM,EACX,QAAQ,CAAC,EACT,UAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KACnC,OAAO,CAAC,CAAC,CAKX,CAAC;AAGF,eAAO,MAAM,UAAU,GAAU,CAAC,EAChC,KAAK,MAAM,EACX,QAAQ,CAAC,EACT,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAK,EACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAC/B,UAAU,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,EAChC,aAAa,MAAM,IAAI,EACvB,SAAS,WAAW,KACnB,OAAO,CAAC,IAAI,CAwDd,CAAC;AAGF,eAAO,MAAM,OAAO,GAAU,CAAC,EAC7B,KAAK,MAAM,EACX,QAAQ,CAAC,EACT,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAK,EACpC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,EAChD,UAAU,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,EAChC,SAAS,WAAW,KACnB,OAAO,CAAC,IAAI,CAiEd,CAAC;AAGF,eAAO,MAAM,OAAO,GAAU,CAAC,EAAE,CAAC,EAChC,KAAK,MAAM,EACX,QAAQ,CAAC,EACT,UAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KACnC,OAAO,CAAC,CAAC,CAKX,CAAC;AAGF,eAAO,MAAM,UAAU,GAAU,CAAC,EAChC,KAAK,MAAM,EACX,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,UAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KACnC,OAAO,CAAC,CAAC,CAGX,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/api/interface.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,GAAG;;;CAGR,CAAC;AAEF,eAAe,GAAG,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* excel转json功能主函数
|
|
4
|
+
* 读取用户输入的excel路径,解析内容,根据配置生成多语言json文件
|
|
5
|
+
* 并对配置文件中所有语言对应的词条进行语言检测
|
|
6
|
+
* @param program Commander命令行实例
|
|
7
|
+
*/
|
|
8
|
+
export declare function excel2json(program: Command): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/excel2json/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyLpC;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,OAAO,iBA8ThD"}
|
|
@@ -95,6 +95,45 @@ async function batchCheckTexts(texts, language) {
|
|
|
95
95
|
}
|
|
96
96
|
return results;
|
|
97
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* 将语言检测结果转换成每条词条对应的错误描述数组
|
|
100
|
+
* @param checkResult 语言检测结果
|
|
101
|
+
* @param texts 词条数组(对应检测文本)
|
|
102
|
+
* @returns 按词条分割的检测错误描述数组,顺序对应输入texts
|
|
103
|
+
*/
|
|
104
|
+
function parseCheckResultPerEntry(checkResult, texts) {
|
|
105
|
+
// 初始化每条词条对应的错误信息数组
|
|
106
|
+
const entryErrors = new Array(texts.length).fill('').map(() => '');
|
|
107
|
+
// 语言检测返回的matches是针对整个拼接文本的,需要拆分到对应词条
|
|
108
|
+
// 计算每条词条在拼接文本中的起始位置和结束位置
|
|
109
|
+
const positions = [];
|
|
110
|
+
let pos = 0;
|
|
111
|
+
for (const text of texts) {
|
|
112
|
+
const len = text.length;
|
|
113
|
+
positions.push({ start: pos, end: pos + len });
|
|
114
|
+
pos += len + 1; // +1是换行符长度
|
|
115
|
+
}
|
|
116
|
+
// 遍历所有错误匹配项,将错误信息分配到对应词条
|
|
117
|
+
for (const match of checkResult.matches) {
|
|
118
|
+
const errorOffset = match.offset;
|
|
119
|
+
// 找出错误所在的词条索引
|
|
120
|
+
const idx = positions.findIndex((range) => errorOffset >= range.start && errorOffset < range.end);
|
|
121
|
+
if (idx === -1)
|
|
122
|
+
continue;
|
|
123
|
+
// 生成错误信息字符串
|
|
124
|
+
const errMsg = `错误: ${match.message}\n出错句子: ${match.sentence}\n建议替换: ${match.replacements
|
|
125
|
+
.map((r) => r.value)
|
|
126
|
+
.join(', ')}`;
|
|
127
|
+
// 多条错误用换行分隔
|
|
128
|
+
if (entryErrors[idx]) {
|
|
129
|
+
entryErrors[idx] += '\n' + errMsg;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
entryErrors[idx] = errMsg;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return entryErrors;
|
|
136
|
+
}
|
|
98
137
|
/**
|
|
99
138
|
* excel转json功能主函数
|
|
100
139
|
* 读取用户输入的excel路径,解析内容,根据配置生成多语言json文件
|
|
@@ -108,9 +147,9 @@ export async function excel2json(program) {
|
|
|
108
147
|
let i18nConfig;
|
|
109
148
|
// 加载配置文件
|
|
110
149
|
try {
|
|
111
|
-
logger.info(`开始加载配置文件:${configPath}
|
|
150
|
+
logger.info(`开始加载配置文件:${configPath}`, true);
|
|
112
151
|
i18nConfig = loadConfig(configPath);
|
|
113
|
-
logger.info('配置文件加载成功');
|
|
152
|
+
logger.info('配置文件加载成功', true);
|
|
114
153
|
}
|
|
115
154
|
catch (error) {
|
|
116
155
|
const msg = `读取配置文件失败:${normalizeError(error).stack},程序已退出`;
|
|
@@ -120,9 +159,9 @@ export async function excel2json(program) {
|
|
|
120
159
|
}
|
|
121
160
|
// 尝试调用接口获取支持的语言列表,更新 longCodes
|
|
122
161
|
try {
|
|
123
|
-
logger.info('尝试获取在线支持的语言列表...');
|
|
162
|
+
logger.info('尝试获取在线支持的语言列表...', true);
|
|
124
163
|
const languageTools = await getLanguageTool();
|
|
125
|
-
logger.info(`成功获取语言列表,覆盖配置文件中的 longCodes
|
|
164
|
+
logger.info(`成功获取语言列表,覆盖配置文件中的 longCodes`, true);
|
|
126
165
|
// 构建新的 longCodes 映射
|
|
127
166
|
const newLongCodes = {};
|
|
128
167
|
// 语言标识对应语言名称列表,方便匹配
|
|
@@ -146,6 +185,7 @@ export async function excel2json(program) {
|
|
|
146
185
|
}
|
|
147
186
|
catch (error) {
|
|
148
187
|
logger.warn(`获取在线语言列表失败,使用本地配置 longCodes,错误:${normalizeError(error).stack}`);
|
|
188
|
+
console.warn('获取在线语言列表失败,使用本地配置 longCodes');
|
|
149
189
|
}
|
|
150
190
|
// 交互式输入excel文件路径并校验
|
|
151
191
|
const answer = await input({
|
|
@@ -164,7 +204,7 @@ export async function excel2json(program) {
|
|
|
164
204
|
// 规范化路径,支持相对路径转绝对路径,去除首尾引号
|
|
165
205
|
const excelPath = path.resolve(process.cwd(), answer.trim().replace(/^['"]|['"]$/g, ''));
|
|
166
206
|
try {
|
|
167
|
-
logger.info(`开始读取excel文件:${excelPath}
|
|
207
|
+
logger.info(`开始读取excel文件:${excelPath}`, true);
|
|
168
208
|
// 读取excel文件
|
|
169
209
|
const workbook = XLSX.readFile(excelPath);
|
|
170
210
|
const firstSheetName = workbook.SheetNames[0];
|
|
@@ -181,7 +221,7 @@ export async function excel2json(program) {
|
|
|
181
221
|
console.error('程序执行时发生异常,已记录日志,程序已退出');
|
|
182
222
|
process.exit(1);
|
|
183
223
|
}
|
|
184
|
-
logger.info('开始解析表头');
|
|
224
|
+
logger.info('开始解析表头', true);
|
|
185
225
|
// 处理表头行,去除空格,转成字符串
|
|
186
226
|
const headerRow = rows[0].map((cell) => (cell ? String(cell).trim() : ''));
|
|
187
227
|
// 根据表头匹配语言列,建立列索引到语言key的映射
|
|
@@ -206,7 +246,7 @@ export async function excel2json(program) {
|
|
|
206
246
|
Object.values(colIndexToLangKey).forEach((langKey) => {
|
|
207
247
|
langTranslations[langKey] = {};
|
|
208
248
|
});
|
|
209
|
-
logger.info('开始解析数据行');
|
|
249
|
+
logger.info('开始解析数据行', true);
|
|
210
250
|
// 遍历数据行,提取所有语言词条
|
|
211
251
|
// key统一用默认语言列的值,其他语言对应的列为翻译内容
|
|
212
252
|
const langKeysMap = {}; // 语言key => 词条数组
|
|
@@ -237,31 +277,47 @@ export async function excel2json(program) {
|
|
|
237
277
|
langTranslations[langKey][key] = valStr;
|
|
238
278
|
langKeysMap[langKey].push(valStr);
|
|
239
279
|
}
|
|
280
|
+
else {
|
|
281
|
+
// 确保检测结果数组长度一致,填空字符串
|
|
282
|
+
langKeysMap[langKey].push('');
|
|
283
|
+
}
|
|
240
284
|
}
|
|
241
285
|
}
|
|
286
|
+
// 语言检测结果映射,语言key => 每条词条的错误描述数组
|
|
287
|
+
const langCheckErrorsMap = {};
|
|
242
288
|
// 对所有语言词条批量进行语言检测(包括默认语言)
|
|
243
|
-
|
|
289
|
+
const langKeysEntries = Object.entries(langKeysMap);
|
|
290
|
+
for (let idx = 0; idx < langKeysEntries.length; idx++) {
|
|
291
|
+
const [langKey, texts] = langKeysEntries[idx];
|
|
244
292
|
const longCode = i18nConfig.longCodes[langKey];
|
|
245
293
|
if (!longCode) {
|
|
246
|
-
logger.warn(`语言(${langKey})未配置 longCode
|
|
294
|
+
logger.warn(`语言(${langKey})未配置 longCode,跳过检测`, true);
|
|
295
|
+
langCheckErrorsMap[langKey] =
|
|
296
|
+
texts.length > 0 ? texts.map(() => '') : [];
|
|
247
297
|
continue;
|
|
248
298
|
}
|
|
249
299
|
if (texts.length === 0) {
|
|
250
|
-
logger.info(`语言(${langKey})
|
|
300
|
+
logger.info(`语言(${langKey})无词条,跳过检测`, true);
|
|
301
|
+
langCheckErrorsMap[langKey] = [];
|
|
251
302
|
continue;
|
|
252
303
|
}
|
|
253
|
-
logger.info(`开始对语言(${langKey})词条进行语言检测,词条数量:${texts.length}
|
|
304
|
+
logger.info(`开始对语言(${langKey})词条进行语言检测,词条数量:${texts.length} (${idx + 1}/${langKeysEntries.length})`, true);
|
|
254
305
|
const checkResults = await batchCheckTexts(texts, longCode);
|
|
255
306
|
if (!checkResults || checkResults.length === 0 || !checkResults[0]) {
|
|
256
|
-
logger.error(`语言(${langKey})
|
|
307
|
+
logger.error(`语言(${langKey})词条检测失败`, true);
|
|
308
|
+
langCheckErrorsMap[langKey] = texts.map(() => '');
|
|
257
309
|
continue;
|
|
258
310
|
}
|
|
259
311
|
const result = checkResults[0];
|
|
260
312
|
if (result.matches.length === 0) {
|
|
261
|
-
logger.info(`语言(${langKey})
|
|
313
|
+
logger.info(`语言(${langKey})词条检测无错误`, true);
|
|
314
|
+
langCheckErrorsMap[langKey] = texts.map(() => '');
|
|
262
315
|
}
|
|
263
316
|
else {
|
|
264
|
-
logger.info(`语言(${langKey})词条检测发现问题,词条数量: ${result.matches.length}
|
|
317
|
+
logger.info(`语言(${langKey})词条检测发现问题,词条数量: ${result.matches.length}`, true);
|
|
318
|
+
// 解析检测结果,拆分到每条词条
|
|
319
|
+
langCheckErrorsMap[langKey] = parseCheckResultPerEntry(result, texts);
|
|
320
|
+
// 详细日志输出
|
|
265
321
|
for (const match of result.matches) {
|
|
266
322
|
logger.info(`- 错误: ${match.message}\n 出错句子: ${match.sentence}\n 建议替换: ${match.replacements
|
|
267
323
|
.map((r) => r.value)
|
|
@@ -276,13 +332,13 @@ export async function excel2json(program) {
|
|
|
276
332
|
if (!fs.existsSync(outputRoot)) {
|
|
277
333
|
fs.mkdirSync(outputRoot, { recursive: true });
|
|
278
334
|
}
|
|
279
|
-
logger.info(`开始生成语言文件,输出目录:${outputRoot}
|
|
335
|
+
logger.info(`开始生成语言文件,输出目录:${outputRoot}`, true);
|
|
280
336
|
// 按语言生成对应的json文件,默认语言的key=value不生成文件
|
|
281
337
|
for (const [langKey, translations] of Object.entries(langTranslations)) {
|
|
282
338
|
if (Object.keys(translations).length === 0)
|
|
283
339
|
continue;
|
|
284
340
|
if (langKey === defaultLang) {
|
|
285
|
-
logger.info(`跳过默认语言(${langKey})的json
|
|
341
|
+
logger.info(`跳过默认语言(${langKey})的json文件生成`, true);
|
|
286
342
|
continue; // 跳过默认语言文件生成
|
|
287
343
|
}
|
|
288
344
|
const langDir = path.join(outputRoot, langKey);
|
|
@@ -293,9 +349,54 @@ export async function excel2json(program) {
|
|
|
293
349
|
fs.writeFileSync(filePath, JSON.stringify(translations, null, 2), {
|
|
294
350
|
encoding: 'utf-8',
|
|
295
351
|
});
|
|
296
|
-
logger.info(`已生成语言文件:${filePath}
|
|
352
|
+
logger.info(`已生成语言文件:${filePath}`, true);
|
|
353
|
+
}
|
|
354
|
+
// 生成语言检测结果excel文件
|
|
355
|
+
logger.info('开始生成语言检测结果excel文件', true);
|
|
356
|
+
// 构造检测结果excel的表头:默认语言列 + 其他语言列(对应原文列名)
|
|
357
|
+
// 这里表头用原excel的表头中对应语言列的值
|
|
358
|
+
const errorSheetHeader = [];
|
|
359
|
+
// 按列索引顺序遍历,匹配语言key,构造表头
|
|
360
|
+
Object.entries(colIndexToLangKey)
|
|
361
|
+
.sort((a, b) => Number(a[0]) - Number(b[0]))
|
|
362
|
+
.forEach(([colIdxStr, langKey]) => {
|
|
363
|
+
const colIdx = Number(colIdxStr);
|
|
364
|
+
// 表头为原excel表头中对应列的文字
|
|
365
|
+
errorSheetHeader.push(headerRow[colIdx]);
|
|
366
|
+
});
|
|
367
|
+
// 构造检测结果excel的内容,每一列对应语言检测错误描述
|
|
368
|
+
// 每行对应原excel中一条数据行
|
|
369
|
+
const dataRowCount = rows.length - 1;
|
|
370
|
+
const errorSheetData = [errorSheetHeader];
|
|
371
|
+
for (let i = 0; i < dataRowCount; i++) {
|
|
372
|
+
const rowErrors = [];
|
|
373
|
+
// 按列索引顺序遍历,填充对应语言的检测错误
|
|
374
|
+
Object.entries(colIndexToLangKey)
|
|
375
|
+
.sort((a, b) => Number(a[0]) - Number(b[0]))
|
|
376
|
+
.forEach(([colIdxStr, langKey]) => {
|
|
377
|
+
var _a;
|
|
378
|
+
const errorsArr = langCheckErrorsMap[langKey];
|
|
379
|
+
if (errorsArr && errorsArr.length > i) {
|
|
380
|
+
// 只展示检测错误,空字符串视为空白
|
|
381
|
+
const err = (_a = errorsArr[i]) === null || _a === void 0 ? void 0 : _a.trim();
|
|
382
|
+
rowErrors.push(err && err.length > 0 ? err : '');
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
rowErrors.push('');
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
errorSheetData.push(rowErrors);
|
|
297
389
|
}
|
|
298
|
-
|
|
390
|
+
// 生成excel工作簿和工作表
|
|
391
|
+
const errorWorkbook = XLSX.utils.book_new();
|
|
392
|
+
const errorSheet = XLSX.utils.aoa_to_sheet(errorSheetData);
|
|
393
|
+
XLSX.utils.book_append_sheet(errorWorkbook, errorSheet, 'LanguageCheckResults');
|
|
394
|
+
// 写入检测结果excel文件,固定文件名 lang_check_results.xlsx
|
|
395
|
+
const errorExcelPath = path.join(outputRoot, `lang_check_results.xlsx`);
|
|
396
|
+
XLSX.writeFile(errorWorkbook, errorExcelPath);
|
|
397
|
+
logger.info(`语言检测结果excel文件已生成:${errorExcelPath}`, true);
|
|
398
|
+
// 最终完成提示,包含输出目录
|
|
399
|
+
logger.info(`全部转换完成,语言文件输出目录:${outputRoot}`, true);
|
|
299
400
|
}
|
|
300
401
|
catch (error) {
|
|
301
402
|
// 记录错误日志,方便排查
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/extractEntry/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAElB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,iBAmE1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/json2excel/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAElB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/i18n/jsonMerge/index.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAElB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取当前时间戳字符串,格式为:YYYYMMDDHHMMSS
|
|
3
|
+
* 例如:20260123135500 表示 2026年01月23日 13点55分00秒
|
|
4
|
+
*
|
|
5
|
+
* @returns {string} 格式化后的时间戳字符串
|
|
6
|
+
*/
|
|
7
|
+
export declare function getTimestamp(): string;
|
|
8
|
+
/**
|
|
9
|
+
* 日志级别类型
|
|
10
|
+
*/
|
|
11
|
+
type LogLevel = 'INFO' | 'WARN' | 'ERROR';
|
|
12
|
+
/**
|
|
13
|
+
* 日志配置接口
|
|
14
|
+
*/
|
|
15
|
+
interface LoggerOptions {
|
|
16
|
+
/**
|
|
17
|
+
* 日志目录,默认根目录下的 logs 文件夹
|
|
18
|
+
*/
|
|
19
|
+
logsDir?: string;
|
|
20
|
+
/**
|
|
21
|
+
* 日志文件名格式函数,接收当前日期,返回文件名字符串
|
|
22
|
+
* 默认格式为 YYYYMMDD.txt
|
|
23
|
+
*/
|
|
24
|
+
filenameFormatter?: (date: Date) => string;
|
|
25
|
+
/**
|
|
26
|
+
* 当前环境,默认 process.env.NODE_ENV
|
|
27
|
+
*/
|
|
28
|
+
env?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 统一日志处理类
|
|
32
|
+
* 支持写入日志文件和控制台打印
|
|
33
|
+
*/
|
|
34
|
+
export declare class Logger {
|
|
35
|
+
private logsDir;
|
|
36
|
+
private filenameFormatter;
|
|
37
|
+
private env;
|
|
38
|
+
/**
|
|
39
|
+
* 构造函数,初始化日志配置
|
|
40
|
+
* @param options 配置项,可选
|
|
41
|
+
*/
|
|
42
|
+
constructor(options?: LoggerOptions);
|
|
43
|
+
/**
|
|
44
|
+
* 写日志主函数
|
|
45
|
+
* @param level 日志级别
|
|
46
|
+
* @param message 日志内容,支持字符串或对象
|
|
47
|
+
* @param printConsole 是否打印到控制台,默认 false
|
|
48
|
+
*/
|
|
49
|
+
log(level: LogLevel, message: unknown, printConsole?: boolean): void;
|
|
50
|
+
/**
|
|
51
|
+
* 记录信息级别日志
|
|
52
|
+
* @param message 日志内容
|
|
53
|
+
* @param printConsole 是否打印到控制台,默认 false
|
|
54
|
+
*/
|
|
55
|
+
info(message: unknown, printConsole?: boolean): void;
|
|
56
|
+
/**
|
|
57
|
+
* 记录警告级别日志
|
|
58
|
+
* @param message 日志内容
|
|
59
|
+
* @param printConsole 是否打印到控制台,默认 false
|
|
60
|
+
*/
|
|
61
|
+
warn(message: unknown, printConsole?: boolean): void;
|
|
62
|
+
/**
|
|
63
|
+
* 记录错误级别日志
|
|
64
|
+
* @param message 日志内容
|
|
65
|
+
* @param printConsole 是否打印到控制台,默认 false
|
|
66
|
+
*/
|
|
67
|
+
error(message: unknown, printConsole?: boolean): void;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 默认导出单例 logger,方便直接使用
|
|
71
|
+
* 默认不打印控制台日志
|
|
72
|
+
*/
|
|
73
|
+
export declare const logger: Logger;
|
|
74
|
+
/**
|
|
75
|
+
* 通用错误日志记录函数
|
|
76
|
+
* @param error 捕获的错误对象
|
|
77
|
+
* @param logger 日志对象,需包含 error 方法
|
|
78
|
+
* @param prefix 日志前缀,方便区分来源,默认值为 '程序执行时发生错误'
|
|
79
|
+
* @param printConsole 是否打印错误日志到控制台,默认 false
|
|
80
|
+
*/
|
|
81
|
+
export declare function loggerError(error: unknown, logger: {
|
|
82
|
+
error: (msg: string, printConsole?: boolean) => void;
|
|
83
|
+
}, prefix?: string, printConsole?: boolean): void;
|
|
84
|
+
/**
|
|
85
|
+
* 将任意错误对象规范化为 Error 类型。
|
|
86
|
+
* @param err - 可能是 Error、字符串或其他任意类型
|
|
87
|
+
* @returns 标准的 Error 对象
|
|
88
|
+
*/
|
|
89
|
+
export declare const normalizeError: (err: unknown) => Error;
|
|
90
|
+
/**
|
|
91
|
+
* 语言工具接口返回的语言列表类型
|
|
92
|
+
* 数组中每个元素包含语言名称、简写代码和长代码
|
|
93
|
+
*/
|
|
94
|
+
export type LanguageTool = {
|
|
95
|
+
name: string;
|
|
96
|
+
code: string;
|
|
97
|
+
longCode: string;
|
|
98
|
+
}[];
|
|
99
|
+
/**
|
|
100
|
+
* 获取支持的语言列表
|
|
101
|
+
* 调用语言工具接口,返回所有支持的语言信息数组
|
|
102
|
+
* @returns Promise<LanguageTool> 返回语言列表的 Promise
|
|
103
|
+
* @throws 接口请求失败时抛出错误,错误信息包含接口地址和异常堆栈
|
|
104
|
+
*/
|
|
105
|
+
export declare function getLanguageTool(): Promise<LanguageTool>;
|
|
106
|
+
/**
|
|
107
|
+
* 替换建议类型
|
|
108
|
+
*/
|
|
109
|
+
export interface Replacement {
|
|
110
|
+
value: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 语言检测结果中的单条匹配错误信息
|
|
114
|
+
*/
|
|
115
|
+
export interface Match {
|
|
116
|
+
message: string;
|
|
117
|
+
shortMessage: string;
|
|
118
|
+
offset: number;
|
|
119
|
+
length: number;
|
|
120
|
+
replacements: Replacement[];
|
|
121
|
+
sentence: string;
|
|
122
|
+
rule: {
|
|
123
|
+
id: string;
|
|
124
|
+
description: string;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 语言检测接口返回的完整结果类型
|
|
129
|
+
*/
|
|
130
|
+
export interface CheckResult {
|
|
131
|
+
matches: Match[];
|
|
132
|
+
language: {
|
|
133
|
+
name: string;
|
|
134
|
+
code: string;
|
|
135
|
+
};
|
|
136
|
+
software: {
|
|
137
|
+
name: string;
|
|
138
|
+
version: string;
|
|
139
|
+
premium: boolean;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 调用语言检测接口,检测文本中的语言错误
|
|
144
|
+
* @param text 待检测文本
|
|
145
|
+
* @param language 语言代码,默认 'en-US'
|
|
146
|
+
* @returns Promise<CheckResult> 返回检测结果的 Promise
|
|
147
|
+
* @throws 接口请求失败时抛出错误,错误信息包含接口地址和异常堆栈
|
|
148
|
+
*/
|
|
149
|
+
export declare function languageToolCheck(text: string, language?: string): Promise<CheckResult>;
|
|
150
|
+
export {};
|
|
151
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAmBrC;AAED;;GAEG;AACH,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1C;;GAEG;AACH,UAAU,aAAa;IACrB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IAE3C;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA8ED;;;GAGG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAyB;IAClD,OAAO,CAAC,GAAG,CAAS;IAEpB;;;OAGG;gBACS,OAAO,CAAC,EAAE,aAAa;IAUnC;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,UAAQ,GAAG,IAAI;IAsClE;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,UAAQ,GAAG,IAAI;IAIlD;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,UAAQ,GAAG,IAAI;IAIlD;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,UAAQ,GAAG,IAAI;CAGpD;AAED;;;GAGG;AACH,eAAO,MAAM,MAAM,QAEjB,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE;IAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,EAChE,MAAM,SAAc,EACpB,YAAY,UAAQ,GACnB,IAAI,CAEN;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,KAAG,KAW7C,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,EAAE,CAAC;AAEJ;;;;;GAKG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAS7D;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QAEJ,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,QAAQ,EAAE;QAER,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,QAAQ,EAAE;QAER,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,SAAU,GACjB,OAAO,CAAC,WAAW,CAAC,CAetB"}
|
package/dist/utils/index.js
CHANGED
|
@@ -27,32 +27,32 @@ export function getTimestamp() {
|
|
|
27
27
|
return `${year}${month}${day}${hour}${minute}${second}`;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @returns
|
|
30
|
+
* 获取项目根目录路径,兼容 ESM
|
|
31
|
+
* @returns 根目录绝对路径
|
|
32
32
|
*/
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (process.argv.length > 1) {
|
|
41
|
-
return path.resolve(process.cwd(), process.argv[1]);
|
|
42
|
-
}
|
|
43
|
-
// 最终兜底
|
|
44
|
-
return '';
|
|
45
|
-
}
|
|
33
|
+
function getRootDir() {
|
|
34
|
+
// 当前模块文件路径
|
|
35
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
36
|
+
// 当前模块目录
|
|
37
|
+
const __dirname = path.dirname(__filename);
|
|
38
|
+
// 根目录为当前模块目录的上两级,视项目结构调整
|
|
39
|
+
return path.resolve(__dirname, '../../');
|
|
46
40
|
}
|
|
47
41
|
/**
|
|
48
42
|
* 默认日志配置
|
|
49
|
-
* logsDir
|
|
43
|
+
* logsDir 默认设置为项目根目录的 logs 文件夹
|
|
50
44
|
*/
|
|
51
45
|
const defaultOptions = {
|
|
52
|
-
logsDir: '',
|
|
53
|
-
filenameFormatter: (date) =>
|
|
46
|
+
logsDir: path.resolve(getRootDir(), 'logs'),
|
|
47
|
+
filenameFormatter: (date) => {
|
|
48
|
+
// 使用本地时间格式化,格式 YYYYMMDD.txt
|
|
49
|
+
const pad = (n) => n.toString().padStart(2, '0');
|
|
50
|
+
const year = date.getFullYear();
|
|
51
|
+
const month = pad(date.getMonth() + 1);
|
|
52
|
+
const day = pad(date.getDate());
|
|
53
|
+
return `${year}${month}${day}.txt`;
|
|
54
|
+
},
|
|
54
55
|
env: process.env.NODE_ENV || 'production',
|
|
55
|
-
entryFilePath: getEntryFilePath(),
|
|
56
56
|
};
|
|
57
57
|
/**
|
|
58
58
|
* 格式化日志内容,支持字符串或对象
|
|
@@ -62,7 +62,24 @@ const defaultOptions = {
|
|
|
62
62
|
* @returns 格式化后的日志字符串
|
|
63
63
|
*/
|
|
64
64
|
function formatLogLine(level, message, date) {
|
|
65
|
-
|
|
65
|
+
// 使用本地时间格式化为 ISO-like 字符串(带时区偏移)
|
|
66
|
+
// 格式示例:2026-01-23T13:55:00+08:00
|
|
67
|
+
function formatLocalISO(date) {
|
|
68
|
+
const pad = (n) => n.toString().padStart(2, '0');
|
|
69
|
+
const year = date.getFullYear();
|
|
70
|
+
const month = pad(date.getMonth() + 1);
|
|
71
|
+
const day = pad(date.getDate());
|
|
72
|
+
const hour = pad(date.getHours());
|
|
73
|
+
const minute = pad(date.getMinutes());
|
|
74
|
+
const second = pad(date.getSeconds());
|
|
75
|
+
// 计算时区偏移,单位分钟
|
|
76
|
+
const tzOffset = -date.getTimezoneOffset();
|
|
77
|
+
const sign = tzOffset >= 0 ? '+' : '-';
|
|
78
|
+
const tzHour = pad(Math.floor(Math.abs(tzOffset) / 60));
|
|
79
|
+
const tzMinute = pad(Math.abs(tzOffset) % 60);
|
|
80
|
+
return `${year}-${month}-${day}T${hour}:${minute}:${second}${sign}${tzHour}:${tzMinute}`;
|
|
81
|
+
}
|
|
82
|
+
const timeStr = formatLocalISO(date);
|
|
66
83
|
let msgStr;
|
|
67
84
|
if (typeof message === 'string') {
|
|
68
85
|
msgStr = message;
|
|
@@ -89,10 +106,8 @@ export class Logger {
|
|
|
89
106
|
constructor(options) {
|
|
90
107
|
var _a, _b;
|
|
91
108
|
const opts = { ...defaultOptions, ...options };
|
|
92
|
-
// 如果未传 logsDir
|
|
93
|
-
this.logsDir =
|
|
94
|
-
opts.logsDir ||
|
|
95
|
-
path.resolve(path.dirname(opts.entryFilePath), '..', 'logs');
|
|
109
|
+
// 如果未传 logsDir,则默认设置为根目录的 logs 文件夹
|
|
110
|
+
this.logsDir = opts.logsDir;
|
|
96
111
|
this.filenameFormatter =
|
|
97
112
|
(_a = opts.filenameFormatter) !== null && _a !== void 0 ? _a : defaultOptions.filenameFormatter;
|
|
98
113
|
this.env = (_b = opts.env) !== null && _b !== void 0 ? _b : defaultOptions.env;
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "td-web-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A CLI tool for efficiency",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"td-web-cli": "dist/index.js"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
10
13
|
"scripts": {
|
|
11
14
|
"build": "tsc",
|
|
12
15
|
"format": "prettier --write \"src/**/*.{js,ts,tsx,json,md}\""
|
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/setting.json
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"i18n": {
|
|
3
|
-
"defaultKey": "en",
|
|
4
|
-
"langs": {
|
|
5
|
-
"cn": ["简体中文"],
|
|
6
|
-
"zh": ["繁体中文"],
|
|
7
|
-
"en": ["英语"],
|
|
8
|
-
"it": ["意大利语"],
|
|
9
|
-
"brpt": ["巴西葡语"],
|
|
10
|
-
"uk": ["乌克兰语"],
|
|
11
|
-
"ru": ["俄语"],
|
|
12
|
-
"es": ["欧洲西语"],
|
|
13
|
-
"hu": ["匈牙利语"],
|
|
14
|
-
"pl": ["波兰语"],
|
|
15
|
-
"tr": ["土耳其语"],
|
|
16
|
-
"de": ["德语"],
|
|
17
|
-
"fr": ["法语"],
|
|
18
|
-
"ro": ["罗马尼亚语"],
|
|
19
|
-
"ko": ["韩语"],
|
|
20
|
-
"cs": ["捷克语"],
|
|
21
|
-
"laes": ["拉美西语"],
|
|
22
|
-
"pt": ["欧洲葡语"],
|
|
23
|
-
"nl": ["荷兰语"]
|
|
24
|
-
},
|
|
25
|
-
"longCodes": {
|
|
26
|
-
"cn": "zh-CN",
|
|
27
|
-
"zh": "zh-TW",
|
|
28
|
-
"en": "en-US",
|
|
29
|
-
"it": "it-IT",
|
|
30
|
-
"brpt": "pt-BR",
|
|
31
|
-
"uk": "uk-UA",
|
|
32
|
-
"ru": "ru-RU",
|
|
33
|
-
"es": "es-ES",
|
|
34
|
-
"hu": "hu-HU",
|
|
35
|
-
"pl": "pl-PL",
|
|
36
|
-
"tr": "tr-TR",
|
|
37
|
-
"de": "de-DE",
|
|
38
|
-
"fr": "fr-FR",
|
|
39
|
-
"ro": "ro-RO",
|
|
40
|
-
"ko": "ko-KR",
|
|
41
|
-
"cs": "cs-CZ",
|
|
42
|
-
"laes": "es-MX",
|
|
43
|
-
"pt": "pt-PT",
|
|
44
|
-
"nl": "nl-NL"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|