@mks2508/better-logger 1.1.0 → 1.2.0
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/.claude/settings.local.json +3 -2
- package/CHANGELOG.md +63 -0
- package/bun.lock +10 -0
- package/dist/Logger.d.ts.map +1 -1
- package/dist/chunks/{Logger-Th9SfADL.js → Logger-BynuRJQf.js} +12 -6
- package/dist/chunks/{Logger-Th9SfADL.js.map → Logger-BynuRJQf.js.map} +1 -1
- package/dist/chunks/{Logger-C9zTFYBh.js → Logger-DMjlVQWi.js} +2 -2
- package/dist/chunks/{Logger-C9zTFYBh.js.map → Logger-DMjlVQWi.js.map} +1 -1
- package/dist/chunks/{ScopedLogger-uAAeJkfA.js → ScopedLogger-Bl56WovH.js} +2 -2
- package/dist/chunks/{ScopedLogger-uAAeJkfA.js.map → ScopedLogger-Bl56WovH.js.map} +1 -1
- package/dist/chunks/{ScopedLogger-HgV_J-ug.js → ScopedLogger-D2HzayKH.js} +2 -2
- package/dist/chunks/{ScopedLogger-HgV_J-ug.js.map → ScopedLogger-D2HzayKH.js.map} +1 -1
- package/dist/chunks/environment--eaTrhRu.js +4 -0
- package/dist/chunks/environment--eaTrhRu.js.map +1 -0
- package/dist/chunks/{environment-wXLQvk5g.js → environment-BanAyF-K.js} +539 -3
- package/dist/chunks/environment-BanAyF-K.js.map +1 -0
- package/dist/chunks/{formatting-CiFnwe1I.js → formatting-BSNvAxLK.js} +2 -2
- package/dist/chunks/{formatting-CiFnwe1I.js.map → formatting-BSNvAxLK.js.map} +1 -1
- package/dist/chunks/{formatting-DIhpRCCk.js → formatting-CgQSWgXR.js} +2 -2
- package/dist/chunks/{formatting-DIhpRCCk.js.map → formatting-CgQSWgXR.js.map} +1 -1
- package/dist/core.cjs +1 -1
- package/dist/core.js +2 -2
- package/dist/exports.cjs +1 -1
- package/dist/exports.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +6 -6
- package/dist/styling.cjs +1 -1
- package/dist/styling.js +3 -3
- package/dist/terminal/terminal-renderer.d.ts +63 -0
- package/dist/terminal/terminal-renderer.d.ts.map +1 -0
- package/dist/utils/adapter.d.ts +48 -0
- package/dist/utils/adapter.d.ts.map +1 -0
- package/dist/utils/environment-detector.d.ts +35 -0
- package/dist/utils/environment-detector.d.ts.map +1 -0
- package/dist/utils/environment.d.ts +1 -1
- package/dist/utils/output.d.ts +7 -2
- package/dist/utils/output.d.ts.map +1 -1
- package/package.json +10 -2
- package/src/Logger.ts +21 -13
- package/src/terminal/terminal-renderer.ts +339 -0
- package/src/utils/adapter.ts +291 -0
- package/src/utils/environment-detector.ts +148 -0
- package/src/utils/output.ts +43 -1
- package/dist/chunks/environment-5I5unY89.js +0 -4
- package/dist/chunks/environment-5I5unY89.js.map +0 -1
- package/dist/chunks/environment-wXLQvk5g.js.map +0 -1
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Renderer - ANSI color rendering for terminal environments
|
|
3
|
+
* Converts CSS-based styling to ANSI escape sequences for terminal output
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { LogLevel } from '../types/index.js';
|
|
7
|
+
import type { LogStyles } from '../types/index.js';
|
|
8
|
+
|
|
9
|
+
export type ANSIStyle = {
|
|
10
|
+
text: string;
|
|
11
|
+
timestamp?: string;
|
|
12
|
+
level?: string;
|
|
13
|
+
prefix?: string;
|
|
14
|
+
message?: string;
|
|
15
|
+
location?: string;
|
|
16
|
+
reset: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class TerminalRenderer {
|
|
20
|
+
private colorCapability: 'full' | 'basic' | 'none';
|
|
21
|
+
|
|
22
|
+
constructor(colorCapability: 'full' | 'basic' | 'none' = 'full') {
|
|
23
|
+
this.colorCapability = colorCapability;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get ANSI color codes for basic colors
|
|
28
|
+
*/
|
|
29
|
+
private getColorCode(color: string, background: boolean = false): string {
|
|
30
|
+
const colorCodes: Record<string, { normal: string; bright: string }> = {
|
|
31
|
+
'black': { normal: '30', bright: '90' },
|
|
32
|
+
'red': { normal: '31', bright: '91' },
|
|
33
|
+
'green': { normal: '32', bright: '92' },
|
|
34
|
+
'yellow': { normal: '33', bright: '93' },
|
|
35
|
+
'blue': { normal: '34', bright: '94' },
|
|
36
|
+
'magenta': { normal: '35', bright: '95' },
|
|
37
|
+
'cyan': { normal: '36', bright: '96' },
|
|
38
|
+
'white': { normal: '37', bright: '97' },
|
|
39
|
+
'gray': { normal: '90', bright: '37' },
|
|
40
|
+
'grey': { normal: '90', bright: '37' }
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const codes = colorCodes[color.toLowerCase()] || { normal: '37', bright: '97' };
|
|
44
|
+
const prefix = background ? '4' : '3';
|
|
45
|
+
return `\x1b[${codes.normal}m`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get ANSI style codes
|
|
50
|
+
*/
|
|
51
|
+
private getStyleCode(styles: string[]): string {
|
|
52
|
+
const styleCodes: Record<string, string> = {
|
|
53
|
+
'bold': '1',
|
|
54
|
+
'dim': '2',
|
|
55
|
+
'italic': '3',
|
|
56
|
+
'underline': '4',
|
|
57
|
+
'reset': '0'
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const codes = styles.map(style => styleCodes[style] || '0').join(';');
|
|
61
|
+
return codes ? `\x1b[${codes}m` : '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Convert log styles to ANSI formatting
|
|
66
|
+
*/
|
|
67
|
+
renderTerminal(
|
|
68
|
+
level: LogLevel,
|
|
69
|
+
message: string,
|
|
70
|
+
timestamp?: string,
|
|
71
|
+
prefix?: string,
|
|
72
|
+
location?: string,
|
|
73
|
+
styles?: LogStyles
|
|
74
|
+
): ANSIStyle {
|
|
75
|
+
const reset = '\x1b[0m';
|
|
76
|
+
const result: ANSIStyle = { text: '', reset };
|
|
77
|
+
|
|
78
|
+
// Apply preset styles if provided
|
|
79
|
+
if (styles) {
|
|
80
|
+
result.timestamp = this.styleTimestamp(timestamp, styles.timestamp);
|
|
81
|
+
result.level = this.styleLevel(level, styles.level);
|
|
82
|
+
result.prefix = this.stylePrefix(prefix, styles.prefix);
|
|
83
|
+
result.message = this.styleMessage(message, styles.message);
|
|
84
|
+
result.location = this.styleLocation(location, styles.location);
|
|
85
|
+
} else {
|
|
86
|
+
// Default styling based on level
|
|
87
|
+
result.timestamp = this.styleTimestamp(timestamp);
|
|
88
|
+
result.level = this.styleLevel(level);
|
|
89
|
+
result.prefix = this.stylePrefix(prefix);
|
|
90
|
+
result.message = this.styleMessage(message);
|
|
91
|
+
result.location = this.styleLocation(location);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Build complete text
|
|
95
|
+
const parts: string[] = [];
|
|
96
|
+
if (result.timestamp) parts.push(result.timestamp);
|
|
97
|
+
if (result.level) parts.push(result.level);
|
|
98
|
+
if (result.prefix) parts.push(result.prefix);
|
|
99
|
+
if (result.message) parts.push(result.message);
|
|
100
|
+
if (result.location) parts.push(result.location);
|
|
101
|
+
|
|
102
|
+
result.text = parts.join(' ') + reset;
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Style timestamp based on preset or defaults
|
|
108
|
+
*/
|
|
109
|
+
private styleTimestamp(timestamp?: string, style?: LogStyles['timestamp']): string {
|
|
110
|
+
if (!timestamp || !style?.show) return '';
|
|
111
|
+
|
|
112
|
+
if (this.colorCapability === 'none') {
|
|
113
|
+
return timestamp;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const dimStyle = this.getStyleCode(['dim']);
|
|
117
|
+
return `${dimStyle}${timestamp}${'\x1b[0m'}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Style level with appropriate colors and formatting
|
|
122
|
+
*/
|
|
123
|
+
private styleLevel(level: LogLevel, style?: LogStyles['level']): string {
|
|
124
|
+
if (!style?.show) return '';
|
|
125
|
+
|
|
126
|
+
const levelText = this.getLevelText(level);
|
|
127
|
+
const levelColors: Record<LogLevel, string> = {
|
|
128
|
+
'debug': 'magenta',
|
|
129
|
+
'info': 'blue',
|
|
130
|
+
'warn': 'yellow',
|
|
131
|
+
'error': 'red',
|
|
132
|
+
'critical': 'red'
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
if (this.colorCapability === 'none') {
|
|
136
|
+
return `[${levelText}]`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const color = levelColors[level] || 'white';
|
|
140
|
+
const colorCode = this.getColorCode(color);
|
|
141
|
+
const boldStyle = this.getStyleCode(['bold']);
|
|
142
|
+
|
|
143
|
+
if (style?.style === 'compact') {
|
|
144
|
+
return `${colorCode}[${levelText}]${'\x1b[0m'}`;
|
|
145
|
+
} else {
|
|
146
|
+
return `${colorCode}${boldStyle}[${levelText}]${'\x1b[0m'}`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Style prefix based on preset
|
|
152
|
+
*/
|
|
153
|
+
private stylePrefix(prefix?: string, style?: LogStyles['prefix']): string {
|
|
154
|
+
if (!prefix || !style?.show) return '';
|
|
155
|
+
|
|
156
|
+
if (this.colorCapability === 'none') {
|
|
157
|
+
return `[${prefix}]`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const colorCode = this.getColorCode('cyan');
|
|
161
|
+
return `${colorCode}[${prefix}]${'\x1b[0m'}`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Style message based on preset
|
|
166
|
+
*/
|
|
167
|
+
private styleMessage(message: string, style?: LogStyles['message']): string {
|
|
168
|
+
if (!style?.show) return message;
|
|
169
|
+
|
|
170
|
+
return message; // Messages usually don't need styling
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Style location (file:line) information
|
|
175
|
+
*/
|
|
176
|
+
private styleLocation(location?: string, style?: LogStyles['location']): string {
|
|
177
|
+
if (!location || !style?.show) return '';
|
|
178
|
+
|
|
179
|
+
if (this.colorCapability === 'none') {
|
|
180
|
+
return `(${location})`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const dimStyle = this.getStyleCode(['dim']);
|
|
184
|
+
if (style?.style === 'clickable') {
|
|
185
|
+
const underlineStyle = this.getStyleCode(['dim', 'underline']);
|
|
186
|
+
return `${underlineStyle}(${location})${'\x1b[0m'}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return `${dimStyle}(${location})${'\x1b[0m'}`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get text representation of log level
|
|
194
|
+
*/
|
|
195
|
+
public getLevelText(level: LogLevel): string {
|
|
196
|
+
const levelMap: Record<LogLevel, string> = {
|
|
197
|
+
'debug': 'DEBUG',
|
|
198
|
+
'info': 'INFO',
|
|
199
|
+
'warn': 'WARN',
|
|
200
|
+
'error': 'ERROR',
|
|
201
|
+
'critical': 'CRITICAL'
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return levelMap[level] || String(level).toUpperCase();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Create cyberpunk-style ANSI rendering
|
|
209
|
+
*/
|
|
210
|
+
renderCyberpunk(
|
|
211
|
+
level: LogLevel,
|
|
212
|
+
message: string,
|
|
213
|
+
timestamp?: string,
|
|
214
|
+
prefix?: string,
|
|
215
|
+
location?: string
|
|
216
|
+
): ANSIStyle {
|
|
217
|
+
const reset = '\x1b[0m';
|
|
218
|
+
const levelColors: Record<LogLevel, string> = {
|
|
219
|
+
'debug': '\x1b[95m', // Bright magenta
|
|
220
|
+
'info': '\x1b[94m', // Bright blue
|
|
221
|
+
'warn': '\x1b[93m', // Bright yellow
|
|
222
|
+
'error': '\x1b[91m', // Bright red
|
|
223
|
+
'critical': '\x1b[91m\x1b[1m' // Bright red + bold
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const parts: string[] = [];
|
|
227
|
+
|
|
228
|
+
if (timestamp) {
|
|
229
|
+
parts.push(`\x1b[90m${timestamp}${reset}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Cyberpunk level styling
|
|
233
|
+
const levelColor = levelColors[level] || '\x1b[97m';
|
|
234
|
+
const bgBlack = '\x1b[40m';
|
|
235
|
+
parts.push(`${bgBlack}${levelColor} ${this.getLevelText(level)} ${reset}`);
|
|
236
|
+
|
|
237
|
+
if (prefix) {
|
|
238
|
+
parts.push(`\x1b[96m[${prefix}]${reset}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
parts.push(message);
|
|
242
|
+
|
|
243
|
+
if (location) {
|
|
244
|
+
parts.push(`\x1b[90m(${location})${reset}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
text: parts.join(' '),
|
|
249
|
+
reset
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create minimal ANSI rendering
|
|
255
|
+
*/
|
|
256
|
+
renderMinimal(
|
|
257
|
+
level: LogLevel,
|
|
258
|
+
message: string,
|
|
259
|
+
timestamp?: string,
|
|
260
|
+
prefix?: string
|
|
261
|
+
): ANSIStyle {
|
|
262
|
+
const reset = '\x1b[0m';
|
|
263
|
+
const levelColors: Record<LogLevel, string> = {
|
|
264
|
+
'debug': '\x1b[95m', // Magenta
|
|
265
|
+
'info': '\x1b[94m', // Blue
|
|
266
|
+
'warn': '\x1b[93m', // Yellow
|
|
267
|
+
'error': '\x1b[91m', // Red
|
|
268
|
+
'critical': '\x1b[91m\x1b[1m' // Red + bold
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const parts: string[] = [];
|
|
272
|
+
|
|
273
|
+
if (timestamp) {
|
|
274
|
+
parts.push(`\x1b[90m${timestamp}${reset}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const levelColor = levelColors[level] || '\x1b[97m';
|
|
278
|
+
parts.push(`${levelColor}${this.getLevelText(level)}:${reset}`);
|
|
279
|
+
|
|
280
|
+
if (prefix) {
|
|
281
|
+
parts.push(`\x1b[96m${prefix}${reset}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
parts.push(message);
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
text: parts.join(' '),
|
|
288
|
+
reset
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Get chalk instance for log level (for compatibility with adapter)
|
|
294
|
+
*/
|
|
295
|
+
public getChalkForLevel(level: LogLevel): any {
|
|
296
|
+
const levelColors: Record<LogLevel, string> = {
|
|
297
|
+
'debug': 'magenta',
|
|
298
|
+
'info': 'blue',
|
|
299
|
+
'warn': 'yellow',
|
|
300
|
+
'error': 'red',
|
|
301
|
+
'critical': 'red'
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
color: (text: string) => {
|
|
306
|
+
const color = levelColors[level] || 'white';
|
|
307
|
+
const colorCode = this.getColorCode(color);
|
|
308
|
+
return `${colorCode}${text}${'\x1b[0m'}`;
|
|
309
|
+
},
|
|
310
|
+
bold: (text: string) => {
|
|
311
|
+
const boldStyle = this.getStyleCode(['bold']);
|
|
312
|
+
return `${boldStyle}${text}${'\x1b[0m'}`;
|
|
313
|
+
},
|
|
314
|
+
dim: (text: string) => {
|
|
315
|
+
const dimStyle = this.getStyleCode(['dim']);
|
|
316
|
+
return `${dimStyle}${text}${'\x1b[0m'}`;
|
|
317
|
+
},
|
|
318
|
+
bgGray: (text: string) => {
|
|
319
|
+
return `\x1b[100m${text}${'\x1b[0m'}`;
|
|
320
|
+
},
|
|
321
|
+
bgBlue: (text: string) => {
|
|
322
|
+
return `\x1b[104m${text}${'\x1b[0m'}`;
|
|
323
|
+
},
|
|
324
|
+
reset: (text: string) => text,
|
|
325
|
+
cyan: {
|
|
326
|
+
bold: (text: string) => {
|
|
327
|
+
const cyan = this.getColorCode('cyan');
|
|
328
|
+
const bold = this.getStyleCode(['bold']);
|
|
329
|
+
return `${cyan}${bold}${text}${'\x1b[0m'}`;
|
|
330
|
+
},
|
|
331
|
+
dim: (text: string) => {
|
|
332
|
+
const cyan = this.getColorCode('cyan');
|
|
333
|
+
const dim = this.getStyleCode(['dim']);
|
|
334
|
+
return `${cyan}${dim}${text}${'\x1b[0m'}`;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS to ANSI Adapter - Converts CSS-based styles to ANSI terminal styles
|
|
3
|
+
* Bridges the gap between browser styling and terminal rendering
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { LogStyles } from '../types/index.js';
|
|
7
|
+
import type { ANSIStyle } from '../terminal/terminal-renderer.js';
|
|
8
|
+
import { TerminalRenderer } from '../terminal/terminal-renderer.js';
|
|
9
|
+
import type { LogLevel } from '../types/index.js';
|
|
10
|
+
import { getColorCapability } from './environment-detector.js';
|
|
11
|
+
|
|
12
|
+
export class CSS2ANSIAdapter {
|
|
13
|
+
private renderer: TerminalRenderer;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
const colorCapability = getColorCapability();
|
|
17
|
+
this.renderer = new TerminalRenderer(colorCapability);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Convert LogStyles to ANSIStyle for terminal rendering
|
|
22
|
+
*/
|
|
23
|
+
adaptStyles(
|
|
24
|
+
level: LogLevel,
|
|
25
|
+
message: string,
|
|
26
|
+
timestamp?: string,
|
|
27
|
+
prefix?: string,
|
|
28
|
+
location?: string,
|
|
29
|
+
styles?: LogStyles,
|
|
30
|
+
presetName?: string
|
|
31
|
+
): ANSIStyle {
|
|
32
|
+
// Special handling for specific presets that need unique terminal representations
|
|
33
|
+
if (presetName) {
|
|
34
|
+
switch (presetName) {
|
|
35
|
+
case 'cyberpunk':
|
|
36
|
+
return this.renderer.renderCyberpunk(level, message, timestamp, prefix, location);
|
|
37
|
+
case 'minimal':
|
|
38
|
+
return this.renderer.renderMinimal(level, message, timestamp, prefix);
|
|
39
|
+
case 'production':
|
|
40
|
+
return this.adaptProductionStyles(level, message, timestamp, prefix, location, styles);
|
|
41
|
+
case 'debug':
|
|
42
|
+
return this.adaptDebugStyles(level, message, timestamp, prefix, location, styles);
|
|
43
|
+
case 'glassmorphism':
|
|
44
|
+
return this.adaptGlassmorphismStyles(level, message, timestamp, prefix, location, styles);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Default adaptation using the renderer
|
|
49
|
+
return this.renderer.renderTerminal(level, message, timestamp, prefix, location, styles);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Adapt production preset for terminal
|
|
54
|
+
*/
|
|
55
|
+
private adaptProductionStyles(
|
|
56
|
+
level: LogLevel,
|
|
57
|
+
message: string,
|
|
58
|
+
timestamp?: string,
|
|
59
|
+
prefix?: string,
|
|
60
|
+
location?: string,
|
|
61
|
+
styles?: LogStyles
|
|
62
|
+
): ANSIStyle {
|
|
63
|
+
const reset = '\x1b[0m';
|
|
64
|
+
const levelChalk = this.renderer.getChalkForLevel(level);
|
|
65
|
+
|
|
66
|
+
const parts: string[] = [];
|
|
67
|
+
|
|
68
|
+
// Production: clean, essential info only
|
|
69
|
+
if (timestamp && styles?.timestamp?.show) {
|
|
70
|
+
parts.push(levelChalk.dim(timestamp));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (styles?.level?.show) {
|
|
74
|
+
parts.push(levelChalk.color(`[${this.renderer['getLevelText'](level)}]`));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Skip prefix in production (as per preset config)
|
|
78
|
+
if (prefix && styles?.prefix?.show) {
|
|
79
|
+
parts.push(levelChalk.dim(`[${prefix}]`));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (message && styles?.message?.show) {
|
|
83
|
+
parts.push(levelChalk.reset(message));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Skip location in production (as per preset config)
|
|
87
|
+
if (location && styles?.location?.show) {
|
|
88
|
+
parts.push(levelChalk.dim(`(${location})`));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
text: parts.join(' ') + reset,
|
|
93
|
+
reset
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Adapt debug preset for terminal
|
|
99
|
+
*/
|
|
100
|
+
private adaptDebugStyles(
|
|
101
|
+
level: LogLevel,
|
|
102
|
+
message: string,
|
|
103
|
+
timestamp?: string,
|
|
104
|
+
prefix?: string,
|
|
105
|
+
location?: string,
|
|
106
|
+
styles?: LogStyles
|
|
107
|
+
): ANSIStyle {
|
|
108
|
+
const reset = '\x1b[0m';
|
|
109
|
+
const levelChalk = this.renderer.getChalkForLevel(level);
|
|
110
|
+
|
|
111
|
+
const parts: string[] = [];
|
|
112
|
+
|
|
113
|
+
// Debug: monospace fonts, detailed info, compact layout
|
|
114
|
+
if (timestamp && styles?.timestamp?.show) {
|
|
115
|
+
parts.push(levelChalk.dim(timestamp));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (styles?.level?.show) {
|
|
119
|
+
if (styles?.level?.style === 'compact') {
|
|
120
|
+
parts.push(levelChalk.color(`[${this.renderer['getLevelText'](level)}]`));
|
|
121
|
+
} else {
|
|
122
|
+
parts.push(levelChalk.bold(`[${this.renderer['getLevelText'](level)}]`));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (prefix && styles?.prefix?.show) {
|
|
127
|
+
if (styles?.prefix?.style === 'compact') {
|
|
128
|
+
parts.push(levelChalk.cyan.dim(`[${prefix}]`));
|
|
129
|
+
} else {
|
|
130
|
+
parts.push(levelChalk.cyan.bold(`[${prefix}]`));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (message && styles?.message?.show) {
|
|
135
|
+
parts.push(levelChalk.reset(message));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Debug usually shows location
|
|
139
|
+
if (location && styles?.location?.show) {
|
|
140
|
+
if (styles?.location?.style === 'clickable') {
|
|
141
|
+
parts.push(levelChalk.dim(`${location} (clickable)`));
|
|
142
|
+
} else {
|
|
143
|
+
parts.push(levelChalk.dim(`(${location})`));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
text: parts.join(' ') + reset,
|
|
149
|
+
reset
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Adapt glassmorphism preset for terminal
|
|
155
|
+
*/
|
|
156
|
+
private adaptGlassmorphismStyles(
|
|
157
|
+
level: LogLevel,
|
|
158
|
+
message: string,
|
|
159
|
+
timestamp?: string,
|
|
160
|
+
prefix?: string,
|
|
161
|
+
location?: string,
|
|
162
|
+
styles?: LogStyles
|
|
163
|
+
): ANSIStyle {
|
|
164
|
+
const reset = '\x1b[0m';
|
|
165
|
+
const levelChalk = this.renderer.getChalkForLevel(level);
|
|
166
|
+
|
|
167
|
+
const parts: string[] = [];
|
|
168
|
+
|
|
169
|
+
// Glassmorphism: subtle, transparent effects
|
|
170
|
+
if (timestamp && styles?.timestamp?.show) {
|
|
171
|
+
parts.push(levelChalk.dim(timestamp));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (styles?.level?.show) {
|
|
175
|
+
// Subtle level styling with dim background effect
|
|
176
|
+
parts.push(levelChalk.bgGray(` ${this.renderer['getLevelText'](level)} `));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (prefix && styles?.prefix?.show) {
|
|
180
|
+
parts.push(levelChalk.bgBlue(`[${prefix}]`));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (message && styles?.message?.show) {
|
|
184
|
+
parts.push(levelChalk.reset(message));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (location && styles?.location?.show) {
|
|
188
|
+
parts.push(levelChalk.dim(`(${location})`));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
text: parts.join(' ') + reset,
|
|
193
|
+
reset
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Convert CSS color values to ANSI-friendly colors
|
|
199
|
+
*/
|
|
200
|
+
adaptColor(cssColor: string): string {
|
|
201
|
+
// Handle hex colors
|
|
202
|
+
if (cssColor.startsWith('#')) {
|
|
203
|
+
return cssColor; // TerminalRenderer will handle this
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Handle RGB colors
|
|
207
|
+
if (cssColor.startsWith('rgb(')) {
|
|
208
|
+
return cssColor; // TerminalRenderer will handle this
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Handle CSS gradients - extract primary color
|
|
212
|
+
if (cssColor.includes('gradient')) {
|
|
213
|
+
return this.extractColorFromGradient(cssColor);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Handle CSS color names
|
|
217
|
+
return this.cssNameToANSI(cssColor);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Extract primary color from CSS gradient
|
|
222
|
+
*/
|
|
223
|
+
private extractColorFromGradient(gradient: string): string {
|
|
224
|
+
// Extract first color from linear-gradient
|
|
225
|
+
const match = gradient.match(/#[0-9a-fA-F]{6}|rgb\([^)]+\)/);
|
|
226
|
+
return match ? match[0] : '#ffffff';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Convert CSS color names to ANSI-compatible names
|
|
231
|
+
*/
|
|
232
|
+
private cssNameToANSI(cssColor: string): string {
|
|
233
|
+
const colorMap: Record<string, string> = {
|
|
234
|
+
'black': 'black',
|
|
235
|
+
'white': 'white',
|
|
236
|
+
'red': 'red',
|
|
237
|
+
'green': 'green',
|
|
238
|
+
'blue': 'blue',
|
|
239
|
+
'yellow': 'yellow',
|
|
240
|
+
'cyan': 'cyan',
|
|
241
|
+
'magenta': 'magenta',
|
|
242
|
+
'gray': 'gray',
|
|
243
|
+
'grey': 'gray',
|
|
244
|
+
'orange': 'yellow',
|
|
245
|
+
'purple': 'magenta',
|
|
246
|
+
'pink': 'red',
|
|
247
|
+
'brown': 'yellow',
|
|
248
|
+
'lightblue': 'cyan',
|
|
249
|
+
'lightgreen': 'green',
|
|
250
|
+
'lightgray': 'gray',
|
|
251
|
+
'lightgrey': 'gray'
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
return colorMap[cssColor.toLowerCase()] || 'white';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Check if a style should be rendered in terminal
|
|
259
|
+
*/
|
|
260
|
+
shouldRenderStyle(styleType: string, styles?: LogStyles): boolean {
|
|
261
|
+
if (!styles) return true;
|
|
262
|
+
|
|
263
|
+
const styleConfig = (styles as any)[styleType];
|
|
264
|
+
return styleConfig?.show !== false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Get renderer instance for advanced usage
|
|
269
|
+
*/
|
|
270
|
+
getRenderer(): TerminalRenderer {
|
|
271
|
+
return this.renderer;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Singleton instance for consistent styling
|
|
276
|
+
export const css2ansiAdapter = new CSS2ANSIAdapter();
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Convenience function for quick style adaptation
|
|
280
|
+
*/
|
|
281
|
+
export function adaptToTerminal(
|
|
282
|
+
level: LogLevel,
|
|
283
|
+
message: string,
|
|
284
|
+
timestamp?: string,
|
|
285
|
+
prefix?: string,
|
|
286
|
+
location?: string,
|
|
287
|
+
styles?: LogStyles,
|
|
288
|
+
presetName?: string
|
|
289
|
+
): ANSIStyle {
|
|
290
|
+
return css2ansiAdapter.adaptStyles(level, message, timestamp, prefix, location, styles, presetName);
|
|
291
|
+
}
|