nexfep 0.4.1 → 0.4.2

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/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "webview",
18
18
  "typescript"
19
19
  ],
20
- "version": "0.4.1",
20
+ "version": "0.4.2",
21
21
  "type": "module",
22
22
  "main": "./index.js",
23
23
  "scripts": {
@@ -40,7 +40,9 @@
40
40
  "src/Application.js",
41
41
  "src/Application.d.ts",
42
42
  "src/Tray.js",
43
- "src/Tray.d.ts"
43
+ "src/Tray.d.ts",
44
+ "src/Logger.js",
45
+ "src/Logger.d.ts"
44
46
  ],
45
47
  "dependencies": {
46
48
  "@webviewjs/webview": "0.4.0"
@@ -0,0 +1,12 @@
1
+ declare class Logger {
2
+ logFilePath: string | undefined;
3
+ constructor(logFilePath?: string);
4
+ __formatConsoleArgs(args: string[]): string;
5
+ __printLog(winid: number, type: string, args: string[], colorANSI?: string, colorRESET?: string): void;
6
+ log(args: string[] | string): void;
7
+ error(args: string[] | string): void;
8
+ warn(args: string[] | string): void;
9
+ info(args: string[] | string): void;
10
+ debug(args: string[] | string): void;
11
+ }
12
+ export { Logger };
package/src/Logger.js ADDED
@@ -0,0 +1,190 @@
1
+ import fs from 'fs';
2
+ class Logger {
3
+ logFilePath;
4
+ constructor(logFilePath) {
5
+ this.logFilePath = logFilePath;
6
+ }
7
+ __formatConsoleArgs(args) {
8
+ if (!Array.isArray(args) || args.length === 0)
9
+ return '';
10
+ const template = args[0];
11
+ if (typeof template !== 'string' || !template.includes('%c')) {
12
+ return args.map(String).join(' ');
13
+ }
14
+ const RESET = '\x1b[0m';
15
+ const parts = template.split(/(%c)/);
16
+ let styleArgIndex = 1;
17
+ let result = '';
18
+ let currentAnsiStyle = '';
19
+ // 命名前景色映射
20
+ const fgColors = {
21
+ black: '\x1b[30m',
22
+ red: '\x1b[31m',
23
+ green: '\x1b[32m',
24
+ yellow: '\x1b[33m',
25
+ blue: '\x1b[34m',
26
+ magenta: '\x1b[35m',
27
+ cyan: '\x1b[36m',
28
+ white: '\x1b[37m',
29
+ gray: '\x1b[90m',
30
+ grey: '\x1b[90m',
31
+ lightred: '\x1b[91m',
32
+ lightgreen: '\x1b[92m',
33
+ lightyellow: '\x1b[93m',
34
+ lightblue: '\x1b[94m',
35
+ lightmagenta: '\x1b[95m',
36
+ lightcyan: '\x1b[96m',
37
+ lightwhite: '\x1b[97m',
38
+ };
39
+ // 命名背景色映射
40
+ const bgColors = {
41
+ black: '\x1b[40m',
42
+ red: '\x1b[41m',
43
+ green: '\x1b[42m',
44
+ yellow: '\x1b[43m',
45
+ blue: '\x1b[44m',
46
+ magenta: '\x1b[45m',
47
+ cyan: '\x1b[46m',
48
+ white: '\x1b[47m',
49
+ };
50
+ // 文字样式:加粗、斜体、下划线
51
+ const textStyles = {
52
+ 'bold': '\x1b[1m',
53
+ 'font-weight:bold': '\x1b[1m',
54
+ 'italic': '\x1b[3m',
55
+ 'font-style:italic': '\x1b[3m',
56
+ 'underline': '\x1b[4m',
57
+ 'text-decoration:underline': '\x1b[4m',
58
+ 'none': RESET,
59
+ };
60
+ /** hex/rgb 转 ANSI 24位真彩色 */
61
+ function colorToAnsi(colorVal, isBg = false) {
62
+ let val = colorVal.trim().toLowerCase();
63
+ // 命名色
64
+ const colorMap = isBg ? bgColors : fgColors;
65
+ if (colorMap[val])
66
+ return colorMap[val];
67
+ // hex #fff #ffffff
68
+ const hexReg = /^#([0-9a-f]{3}|[0-9a-f]{6})$/;
69
+ if (hexReg.test(val)) {
70
+ let hex = val.replace('#', '');
71
+ if (hex.length === 3)
72
+ hex = hex.split('').map(c => c + c).join('');
73
+ const r = parseInt(hex.slice(0, 2), 16);
74
+ const g = parseInt(hex.slice(2, 4), 16);
75
+ const b = parseInt(hex.slice(4, 6), 16);
76
+ return isBg ? `\x1b[48;2;${r};${g};${b}m` : `\x1b[38;2;${r};${g};${b}m`;
77
+ }
78
+ // rgb(r,g,b)
79
+ const rgbReg = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;
80
+ const rgbMatch = val.match(rgbReg);
81
+ if (rgbMatch) {
82
+ const [, r, g, b] = rgbMatch;
83
+ return isBg ? `\x1b[48;2;${r};${g};${b}m` : `\x1b[38;2;${r};${g};${b}m`;
84
+ }
85
+ return '';
86
+ }
87
+ /** 解析CSS样式字符串为ANSI序列 */
88
+ function parseColorStyle(styleStr) {
89
+ if (!styleStr)
90
+ return RESET;
91
+ let ansi = '';
92
+ const rules = styleStr.split(';').map(s => s.trim()).filter(Boolean);
93
+ for (const rule of rules) {
94
+ const [prop, ...rest] = rule.split(':');
95
+ const propKey = prop.trim().toLowerCase();
96
+ const value = rest.join(':').trim().toLowerCase();
97
+ // 文字样式
98
+ if (textStyles[`${propKey}:${value}`] || textStyles[value]) {
99
+ ansi += textStyles[`${propKey}:${value}`] ?? textStyles[value];
100
+ continue;
101
+ }
102
+ // 前景色
103
+ if (propKey === 'color') {
104
+ ansi += colorToAnsi(value, false);
105
+ continue;
106
+ }
107
+ // 背景色
108
+ if (propKey === 'background' || propKey === 'background-color') {
109
+ ansi += colorToAnsi(value, true);
110
+ continue;
111
+ }
112
+ }
113
+ return ansi;
114
+ }
115
+ for (const segment of parts) {
116
+ if (segment === '%c') {
117
+ // 取出下一个样式参数,参数不足则重置样式
118
+ const styleStr = args[styleArgIndex];
119
+ styleArgIndex++;
120
+ currentAnsiStyle = parseColorStyle(String(styleStr ?? ''));
121
+ }
122
+ else {
123
+ if (segment === '')
124
+ continue;
125
+ if (currentAnsiStyle) {
126
+ result += currentAnsiStyle + segment;
127
+ }
128
+ else {
129
+ result += segment;
130
+ }
131
+ }
132
+ }
133
+ // 全局末尾统一重置,防止后续日志被染色
134
+ if (currentAnsiStyle)
135
+ result += RESET;
136
+ // 剩余非样式参数直接拼接
137
+ const extraArgs = args.slice(styleArgIndex);
138
+ if (extraArgs.length) {
139
+ result += ' ' + extraArgs.map(String).join(' ');
140
+ }
141
+ return result;
142
+ }
143
+ __printLog(winid, type, args, colorANSI, colorRESET) {
144
+ if (this.logFilePath) {
145
+ fs.appendFileSync(this.logFilePath, `${new Date().toISOString()} [${winid}] ${type}: ${args.join(' ')}\n`);
146
+ }
147
+ console.log(`${colorANSI || ''}[${winid}] ${type}:${colorRESET || ''}`, this.__formatConsoleArgs(args));
148
+ }
149
+ log(args) {
150
+ if (Array.isArray(args)) {
151
+ this.__printLog(0, 'Log', args);
152
+ }
153
+ else {
154
+ this.__printLog(0, 'Log', [args]);
155
+ }
156
+ }
157
+ error(args) {
158
+ if (Array.isArray(args)) {
159
+ this.__printLog(0, 'Error', args, '\x1b[31m', '\x1b[0m');
160
+ }
161
+ else {
162
+ this.__printLog(0, 'Error', [args], '\x1b[31m', '\x1b[0m');
163
+ }
164
+ }
165
+ warn(args) {
166
+ if (Array.isArray(args)) {
167
+ this.__printLog(0, 'Warn', args, '\x1b[33m', '\x1b[0m');
168
+ }
169
+ else {
170
+ this.__printLog(0, 'Warn', [args], '\x1b[33m', '\x1b[0m');
171
+ }
172
+ }
173
+ info(args) {
174
+ if (Array.isArray(args)) {
175
+ this.__printLog(0, 'Info', args, '\x1b[34m', '\x1b[0m');
176
+ }
177
+ else {
178
+ this.__printLog(0, 'Info', [args], '\x1b[34m', '\x1b[0m');
179
+ }
180
+ }
181
+ debug(args) {
182
+ if (Array.isArray(args)) {
183
+ this.__printLog(0, 'Debug', args, '\x1b[90m', '\x1b[0m');
184
+ }
185
+ else {
186
+ this.__printLog(0, 'Debug', [args], '\x1b[90m', '\x1b[0m');
187
+ }
188
+ }
189
+ }
190
+ export { Logger };