td-web-cli 0.1.6 → 0.1.8

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.
@@ -1,367 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { getData, postData } from '../api/index.js';
5
- import api from '../api/interface.js';
6
-
7
- /**
8
- * 获取当前时间戳字符串,格式为:YYYYMMDDHHMMSS
9
- * 例如:20260123135500 表示 2026年01月23日 13点55分00秒
10
- *
11
- * @returns {string} 格式化后的时间戳字符串
12
- */
13
- export function getTimestamp(): string {
14
- const now = new Date();
15
-
16
- /**
17
- * 辅助函数:将数字转换为长度为2的字符串,不足时左侧补0
18
- * @param n 需要格式化的数字
19
- * @returns {string} 补零后的字符串
20
- */
21
- const pad = (n: number): string => n.toString().padStart(2, '0');
22
-
23
- const year = now.getFullYear(); // 获取四位年份
24
- const month = pad(now.getMonth() + 1); // 获取月份(0-11),需+1,补零
25
- const day = pad(now.getDate()); // 获取日期,补零
26
- const hour = pad(now.getHours()); // 获取小时,补零
27
- const minute = pad(now.getMinutes()); // 获取分钟,补零
28
- const second = pad(now.getSeconds()); // 获取秒钟,补零
29
-
30
- // 拼接成完整时间戳字符串
31
- return `${year}${month}${day}${hour}${minute}${second}`;
32
- }
33
-
34
- /**
35
- * 日志级别类型
36
- */
37
- type LogLevel = 'INFO' | 'WARN' | 'ERROR';
38
-
39
- /**
40
- * 日志配置接口
41
- */
42
- interface LoggerOptions {
43
- /**
44
- * 日志目录,默认根目录下的 logs 文件夹
45
- */
46
- logsDir?: string;
47
-
48
- /**
49
- * 日志文件名格式函数,接收当前日期,返回文件名字符串
50
- * 默认格式为 YYYYMMDD.txt
51
- */
52
- filenameFormatter?: (date: Date) => string;
53
-
54
- /**
55
- * 当前环境,默认 process.env.NODE_ENV
56
- */
57
- env?: string;
58
- }
59
-
60
- /**
61
- * 获取项目根目录路径,兼容 ESM
62
- * @returns 根目录绝对路径
63
- */
64
- function getRootDir(): string {
65
- // 当前模块文件路径
66
- const __filename = fileURLToPath(import.meta.url);
67
- // 当前模块目录
68
- const __dirname = path.dirname(__filename);
69
- // 根目录为当前模块目录的上两级,视项目结构调整
70
- return path.resolve(__dirname, '../../');
71
- }
72
-
73
- /**
74
- * 默认日志配置
75
- * logsDir 默认设置为项目根目录的 logs 文件夹
76
- */
77
- const defaultOptions: LoggerOptions = {
78
- logsDir: path.resolve(getRootDir(), 'logs'),
79
- filenameFormatter: (date: Date) => {
80
- // 使用本地时间格式化,格式 YYYYMMDD.txt
81
- const pad = (n: number) => n.toString().padStart(2, '0');
82
- const year = date.getFullYear();
83
- const month = pad(date.getMonth() + 1);
84
- const day = pad(date.getDate());
85
- return `${year}${month}${day}.txt`;
86
- },
87
- env: process.env.NODE_ENV || 'production',
88
- };
89
-
90
- /**
91
- * 格式化日志内容,支持字符串或对象
92
- * @param level 日志级别
93
- * @param message 日志内容,字符串或对象
94
- * @param date 当前时间
95
- * @returns 格式化后的日志字符串
96
- */
97
- function formatLogLine(level: LogLevel, message: unknown, date: Date): string {
98
- // 使用本地时间格式化为 ISO-like 字符串(带时区偏移)
99
- // 格式示例:2026-01-23T13:55:00+08:00
100
- function formatLocalISO(date: Date): string {
101
- const pad = (n: number) => n.toString().padStart(2, '0');
102
-
103
- const year = date.getFullYear();
104
- const month = pad(date.getMonth() + 1);
105
- const day = pad(date.getDate());
106
- const hour = pad(date.getHours());
107
- const minute = pad(date.getMinutes());
108
- const second = pad(date.getSeconds());
109
-
110
- // 计算时区偏移,单位分钟
111
- const tzOffset = -date.getTimezoneOffset();
112
- const sign = tzOffset >= 0 ? '+' : '-';
113
- const tzHour = pad(Math.floor(Math.abs(tzOffset) / 60));
114
- const tzMinute = pad(Math.abs(tzOffset) % 60);
115
-
116
- return `${year}-${month}-${day}T${hour}:${minute}:${second}${sign}${tzHour}:${tzMinute}`;
117
- }
118
-
119
- const timeStr = formatLocalISO(date);
120
-
121
- let msgStr: string;
122
-
123
- if (typeof message === 'string') {
124
- msgStr = message;
125
- } else {
126
- try {
127
- msgStr = JSON.stringify(message, null, 2);
128
- } catch {
129
- msgStr = String(message);
130
- }
131
- }
132
-
133
- return `[${timeStr}] [${level}] ${msgStr}\n`;
134
- }
135
-
136
- /**
137
- * 统一日志处理类
138
- * 支持写入日志文件和控制台打印
139
- */
140
- export class Logger {
141
- private logsDir: string;
142
- private filenameFormatter: (date: Date) => string;
143
- private env: string;
144
-
145
- /**
146
- * 构造函数,初始化日志配置
147
- * @param options 配置项,可选
148
- */
149
- constructor(options?: LoggerOptions) {
150
- const opts = { ...defaultOptions, ...options };
151
-
152
- // 如果未传 logsDir,则默认设置为根目录的 logs 文件夹
153
- this.logsDir = opts.logsDir!;
154
- this.filenameFormatter =
155
- opts.filenameFormatter ?? defaultOptions.filenameFormatter!;
156
- this.env = opts.env ?? defaultOptions.env!;
157
- }
158
-
159
- /**
160
- * 写日志主函数
161
- * @param level 日志级别
162
- * @param message 日志内容,支持字符串或对象
163
- * @param printConsole 是否打印到控制台,默认 false
164
- */
165
- log(level: LogLevel, message: unknown, printConsole = false): void {
166
- const now = new Date();
167
- const logLine = formatLogLine(level, message, now);
168
-
169
- // 根据调用时是否指定打印控制台,决定是否打印
170
- if (printConsole) {
171
- switch (level) {
172
- case 'INFO':
173
- console.info(logLine.trim());
174
- break;
175
- case 'WARN':
176
- console.warn(logLine.trim());
177
- break;
178
- case 'ERROR':
179
- console.error(logLine.trim());
180
- break;
181
- }
182
- }
183
-
184
- try {
185
- // 确保日志目录存在
186
- if (!fs.existsSync(this.logsDir)) {
187
- fs.mkdirSync(this.logsDir, { recursive: true });
188
- }
189
-
190
- const filename = this.filenameFormatter(now);
191
- const logFilePath = path.join(this.logsDir, filename);
192
-
193
- // 追加写入日志文件
194
- fs.appendFileSync(logFilePath, logLine, { encoding: 'utf8' });
195
- } catch (error: unknown) {
196
- // 仅在开发环境打印写日志异常堆栈,生产环境静默失败,避免影响主程序
197
- if (this.env === 'development') {
198
- console.error('日志写入异常:', normalizeError(error).stack);
199
- }
200
- }
201
- }
202
-
203
- /**
204
- * 记录信息级别日志
205
- * @param message 日志内容
206
- * @param printConsole 是否打印到控制台,默认 false
207
- */
208
- info(message: unknown, printConsole = false): void {
209
- this.log('INFO', message, printConsole);
210
- }
211
-
212
- /**
213
- * 记录警告级别日志
214
- * @param message 日志内容
215
- * @param printConsole 是否打印到控制台,默认 false
216
- */
217
- warn(message: unknown, printConsole = false): void {
218
- this.log('WARN', message, printConsole);
219
- }
220
-
221
- /**
222
- * 记录错误级别日志
223
- * @param message 日志内容
224
- * @param printConsole 是否打印到控制台,默认 false
225
- */
226
- error(message: unknown, printConsole = false): void {
227
- this.log('ERROR', message, printConsole);
228
- }
229
- }
230
-
231
- /**
232
- * 默认导出单例 logger,方便直接使用
233
- * 默认不打印控制台日志
234
- */
235
- export const logger = new Logger({
236
- env: process.env.NODE_ENV || 'development',
237
- });
238
-
239
- /**
240
- * 通用错误日志记录函数
241
- * @param error 捕获的错误对象
242
- * @param logger 日志对象,需包含 error 方法
243
- * @param prefix 日志前缀,方便区分来源,默认值为 '程序执行时发生错误'
244
- * @param printConsole 是否打印错误日志到控制台,默认 false
245
- */
246
- export function loggerError(
247
- error: unknown,
248
- logger: { error: (msg: string, printConsole?: boolean) => void },
249
- prefix = '程序执行时发生错误',
250
- printConsole = false
251
- ): void {
252
- logger.error(`${prefix}:${normalizeError(error).stack}`, printConsole);
253
- }
254
-
255
- /**
256
- * 将任意错误对象规范化为 Error 类型。
257
- * @param err - 可能是 Error、字符串或其他任意类型
258
- * @returns 标准的 Error 对象
259
- */
260
- export const normalizeError = (err: unknown): Error => {
261
- if (err instanceof Error) {
262
- // 已经是 Error 类型,直接返回
263
- return err;
264
- } else if (typeof err === 'string') {
265
- // 如果是字符串,创建新的 Error
266
- return new Error(err);
267
- } else {
268
- // 其他情况,返回通用错误
269
- return new Error('未知错误');
270
- }
271
- };
272
-
273
- /**
274
- * 语言工具接口返回的语言列表类型
275
- * 数组中每个元素包含语言名称、简写代码和长代码
276
- */
277
- export type LanguageTool = {
278
- name: string; // 语言名称,如 "English"
279
- code: string; // 语言简写代码,如 "en"
280
- longCode: string; // 语言长代码,如 "en-US"
281
- }[];
282
-
283
- /**
284
- * 获取支持的语言列表
285
- * 调用语言工具接口,返回所有支持的语言信息数组
286
- * @returns Promise<LanguageTool> 返回语言列表的 Promise
287
- * @throws 接口请求失败时抛出错误,错误信息包含接口地址和异常堆栈
288
- */
289
- export async function getLanguageTool(): Promise<LanguageTool> {
290
- const url = api.LANGUAGE_TOOL_V2_LANGUAGES;
291
- try {
292
- const res = await getData<LanguageTool>(url);
293
- return res;
294
- } catch (error) {
295
- // 捕获异常并包装错误信息,包含接口地址和堆栈信息
296
- throw new Error(`${url}接口报错:${normalizeError(error).stack}`);
297
- }
298
- }
299
-
300
- /**
301
- * 替换建议类型
302
- */
303
- export interface Replacement {
304
- value: string; // 建议替换的字符串
305
- }
306
-
307
- /**
308
- * 语言检测结果中的单条匹配错误信息
309
- */
310
- export interface Match {
311
- message: string; // 错误描述信息
312
- shortMessage: string; // 简短错误信息
313
- offset: number; // 错误在文本中的起始位置
314
- length: number; // 错误长度
315
- replacements: Replacement[]; // 建议的替换项数组
316
- sentence: string; // 出错的句子
317
- rule: {
318
- // 触发的规则信息
319
- id: string; // 规则ID
320
- description: string; // 规则描述
321
- };
322
- }
323
-
324
- /**
325
- * 语言检测接口返回的完整结果类型
326
- */
327
- export interface CheckResult {
328
- matches: Match[]; // 检测到的所有错误匹配项
329
- language: {
330
- // 语言信息
331
- name: string; // 语言名称
332
- code: string; // 语言代码
333
- };
334
- software: {
335
- // 使用的检测软件信息
336
- name: string; // 软件名称
337
- version: string; // 版本号
338
- premium: boolean; // 是否为付费版
339
- };
340
- }
341
-
342
- /**
343
- * 调用语言检测接口,检测文本中的语言错误
344
- * @param text 待检测文本
345
- * @param language 语言代码,默认 'en-US'
346
- * @returns Promise<CheckResult> 返回检测结果的 Promise
347
- * @throws 接口请求失败时抛出错误,错误信息包含接口地址和异常堆栈
348
- */
349
- export async function languageToolCheck(
350
- text: string,
351
- language = 'en-US'
352
- ): Promise<CheckResult> {
353
- const url = api.LANGUAGE_TOOL_V2_CHECK;
354
- const params = new URLSearchParams();
355
- params.append('text', text);
356
- params.append('language', language);
357
-
358
- try {
359
- const res = await postData<string, CheckResult>(url, params.toString(), {
360
- 'Content-Type': 'application/x-www-form-urlencoded',
361
- });
362
- return res;
363
- } catch (error) {
364
- // 捕获异常并包装错误信息,包含接口地址和堆栈信息
365
- throw new Error(`${url}接口报错:${normalizeError(error).stack}`);
366
- }
367
- }
package/tsconfig.json DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2019",
4
- "module": "nodenext",
5
- "outDir": "./dist",
6
- "rootDir": "./src",
7
- "esModuleInterop": true,
8
- "forceConsistentCasingInFileNames": true,
9
- "strict": true,
10
- "skipLibCheck": true
11
- }
12
- }