@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.
Files changed (46) hide show
  1. package/.claude/settings.local.json +3 -2
  2. package/CHANGELOG.md +63 -0
  3. package/bun.lock +10 -0
  4. package/dist/Logger.d.ts.map +1 -1
  5. package/dist/chunks/{Logger-Th9SfADL.js → Logger-BynuRJQf.js} +12 -6
  6. package/dist/chunks/{Logger-Th9SfADL.js.map → Logger-BynuRJQf.js.map} +1 -1
  7. package/dist/chunks/{Logger-C9zTFYBh.js → Logger-DMjlVQWi.js} +2 -2
  8. package/dist/chunks/{Logger-C9zTFYBh.js.map → Logger-DMjlVQWi.js.map} +1 -1
  9. package/dist/chunks/{ScopedLogger-uAAeJkfA.js → ScopedLogger-Bl56WovH.js} +2 -2
  10. package/dist/chunks/{ScopedLogger-uAAeJkfA.js.map → ScopedLogger-Bl56WovH.js.map} +1 -1
  11. package/dist/chunks/{ScopedLogger-HgV_J-ug.js → ScopedLogger-D2HzayKH.js} +2 -2
  12. package/dist/chunks/{ScopedLogger-HgV_J-ug.js.map → ScopedLogger-D2HzayKH.js.map} +1 -1
  13. package/dist/chunks/environment--eaTrhRu.js +4 -0
  14. package/dist/chunks/environment--eaTrhRu.js.map +1 -0
  15. package/dist/chunks/{environment-wXLQvk5g.js → environment-BanAyF-K.js} +539 -3
  16. package/dist/chunks/environment-BanAyF-K.js.map +1 -0
  17. package/dist/chunks/{formatting-CiFnwe1I.js → formatting-BSNvAxLK.js} +2 -2
  18. package/dist/chunks/{formatting-CiFnwe1I.js.map → formatting-BSNvAxLK.js.map} +1 -1
  19. package/dist/chunks/{formatting-DIhpRCCk.js → formatting-CgQSWgXR.js} +2 -2
  20. package/dist/chunks/{formatting-DIhpRCCk.js.map → formatting-CgQSWgXR.js.map} +1 -1
  21. package/dist/core.cjs +1 -1
  22. package/dist/core.js +2 -2
  23. package/dist/exports.cjs +1 -1
  24. package/dist/exports.js +2 -2
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.js +6 -6
  27. package/dist/styling.cjs +1 -1
  28. package/dist/styling.js +3 -3
  29. package/dist/terminal/terminal-renderer.d.ts +63 -0
  30. package/dist/terminal/terminal-renderer.d.ts.map +1 -0
  31. package/dist/utils/adapter.d.ts +48 -0
  32. package/dist/utils/adapter.d.ts.map +1 -0
  33. package/dist/utils/environment-detector.d.ts +35 -0
  34. package/dist/utils/environment-detector.d.ts.map +1 -0
  35. package/dist/utils/environment.d.ts +1 -1
  36. package/dist/utils/output.d.ts +7 -2
  37. package/dist/utils/output.d.ts.map +1 -1
  38. package/package.json +10 -2
  39. package/src/Logger.ts +21 -13
  40. package/src/terminal/terminal-renderer.ts +339 -0
  41. package/src/utils/adapter.ts +291 -0
  42. package/src/utils/environment-detector.ts +148 -0
  43. package/src/utils/output.ts +43 -1
  44. package/dist/chunks/environment-5I5unY89.js +0 -4
  45. package/dist/chunks/environment-5I5unY89.js.map +0 -1
  46. 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
+ }