@mks2508/better-logger 3.0.0 → 4.0.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 -1
- package/CHANGELOG.json +98 -1
- package/dist/Logger.d.ts +24 -12
- package/dist/Logger.d.ts.map +1 -1
- package/dist/chunks/{Logger-C126NTrD.js → Logger-D-gmmgR2.js} +207 -18
- package/dist/chunks/Logger-D-gmmgR2.js.map +1 -0
- package/dist/chunks/Logger-D7cfaz15.js +2 -0
- package/dist/chunks/Logger-D7cfaz15.js.map +1 -0
- package/dist/chunks/{environment-TI2ByCPT.js → environment-COWvu6Wz.js} +466 -98
- package/dist/chunks/environment-COWvu6Wz.js.map +1 -0
- package/dist/chunks/environment-C_8J-zQ_.js +4 -0
- package/dist/chunks/environment-C_8J-zQ_.js.map +1 -0
- package/dist/chunks/{formatting-CuNUqGks.js → formatting-CYjT9yhO.js} +2 -2
- package/dist/chunks/{formatting-CuNUqGks.js.map → formatting-CYjT9yhO.js.map} +1 -1
- package/dist/chunks/{formatting-Blwy-f0W.js → formatting-Cg5YhB9Y.js} +2 -2
- package/dist/chunks/{formatting-Blwy-f0W.js.map → formatting-Cg5YhB9Y.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.cjs.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +151 -20
- package/dist/index.js.map +1 -1
- package/dist/styling.cjs +1 -1
- package/dist/styling.js +3 -3
- package/dist/terminal/color-converter.d.ts +73 -0
- package/dist/terminal/color-converter.d.ts.map +1 -0
- package/dist/terminal/formatter.d.ts +20 -0
- package/dist/terminal/formatter.d.ts.map +1 -0
- package/dist/terminal/terminal-renderer.d.ts +20 -6
- package/dist/terminal/terminal-renderer.d.ts.map +1 -1
- package/dist/types/core.d.ts +61 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/environment-detector.d.ts +10 -0
- package/dist/utils/environment-detector.d.ts.map +1 -1
- package/dist/writers/BufferWriter.d.ts +96 -0
- package/dist/writers/BufferWriter.d.ts.map +1 -0
- package/dist/writers/index.d.ts +6 -0
- package/dist/writers/index.d.ts.map +1 -0
- package/package.json +1 -1
- package/packages/core/package.json +1 -1
- package/packages/styling/package.json +2 -2
- package/src/Logger.ts +63 -21
- package/src/index.ts +61 -2
- package/src/terminal/color-converter.ts +315 -0
- package/src/terminal/formatter.ts +236 -0
- package/src/terminal/terminal-renderer.ts +74 -79
- package/src/types/core.ts +68 -0
- package/src/types/index.ts +5 -0
- package/src/utils/environment-detector.ts +23 -1
- package/src/writers/BufferWriter.ts +157 -0
- package/src/writers/index.ts +6 -0
- package/dist/chunks/Logger-BCfx_yCK.js +0 -2
- package/dist/chunks/Logger-BCfx_yCK.js.map +0 -1
- package/dist/chunks/Logger-C126NTrD.js.map +0 -1
- package/dist/chunks/environment-Ba5kShbx.js +0 -4
- package/dist/chunks/environment-Ba5kShbx.js.map +0 -1
- package/dist/chunks/environment-TI2ByCPT.js.map +0 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Formatter - Alignment, key-value, and advanced terminal formatting
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getTerminalWidth } from '../utils/environment-detector.js';
|
|
6
|
+
import { getANSIForeground, ANSI, type ColorCapability } from './color-converter.js';
|
|
7
|
+
import type { ColumnConfig, ColumnAlign, BadgeStyle, TimestampFormat, LogOptions } from '../types/index.js';
|
|
8
|
+
|
|
9
|
+
export function stripAnsi(str: string): string {
|
|
10
|
+
return str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getVisibleLength(str: string): number {
|
|
14
|
+
return stripAnsi(str).length;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function padToWidth(str: string, width: number, align: ColumnAlign = 'left'): string {
|
|
18
|
+
const visibleLen = getVisibleLength(str);
|
|
19
|
+
if (visibleLen >= width) return str;
|
|
20
|
+
|
|
21
|
+
const padding = width - visibleLen;
|
|
22
|
+
|
|
23
|
+
switch (align) {
|
|
24
|
+
case 'right':
|
|
25
|
+
return ' '.repeat(padding) + str;
|
|
26
|
+
case 'center':
|
|
27
|
+
const leftPad = Math.floor(padding / 2);
|
|
28
|
+
const rightPad = padding - leftPad;
|
|
29
|
+
return ' '.repeat(leftPad) + str + ' '.repeat(rightPad);
|
|
30
|
+
case 'left':
|
|
31
|
+
default:
|
|
32
|
+
return str + ' '.repeat(padding);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function formatWithRightAlign(
|
|
37
|
+
leftContent: string,
|
|
38
|
+
rightContent: string,
|
|
39
|
+
maxWidth?: number
|
|
40
|
+
): string {
|
|
41
|
+
const width = maxWidth ?? getTerminalWidth();
|
|
42
|
+
const leftLen = getVisibleLength(leftContent);
|
|
43
|
+
const rightLen = getVisibleLength(rightContent);
|
|
44
|
+
|
|
45
|
+
const gap = width - leftLen - rightLen;
|
|
46
|
+
if (gap <= 1) {
|
|
47
|
+
return `${leftContent} ${rightContent}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return `${leftContent}${' '.repeat(gap)}${rightContent}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function formatColumns(
|
|
54
|
+
columns: ColumnConfig[],
|
|
55
|
+
maxWidth?: number,
|
|
56
|
+
colorCapability: ColorCapability = 'full'
|
|
57
|
+
): string {
|
|
58
|
+
const width = maxWidth ?? getTerminalWidth();
|
|
59
|
+
const totalColumns = columns.length;
|
|
60
|
+
|
|
61
|
+
const columnsWithWidths = columns.map((col, idx) => {
|
|
62
|
+
if (col.width) return { ...col, calculatedWidth: col.width };
|
|
63
|
+
|
|
64
|
+
const remainingWidth = width - columns
|
|
65
|
+
.filter((c, i) => i !== idx && c.width)
|
|
66
|
+
.reduce((sum, c) => sum + (c.width ?? 0), 0);
|
|
67
|
+
|
|
68
|
+
const autoColumns = columns.filter(c => !c.width).length;
|
|
69
|
+
const calculatedWidth = Math.floor(remainingWidth / autoColumns);
|
|
70
|
+
|
|
71
|
+
return { ...col, calculatedWidth };
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return columnsWithWidths.map(col => {
|
|
75
|
+
let content = col.content;
|
|
76
|
+
|
|
77
|
+
if (col.color && colorCapability !== 'none') {
|
|
78
|
+
const colorCode = getANSIForeground(col.color, colorCapability);
|
|
79
|
+
content = `${colorCode}${content}${ANSI.reset}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return padToWidth(content, col.calculatedWidth, col.align);
|
|
83
|
+
}).join('');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function formatKeyValue(
|
|
87
|
+
obj: Record<string, unknown>,
|
|
88
|
+
colorCapability: ColorCapability = 'full',
|
|
89
|
+
options: { separator?: string; keyColor?: string; valueColor?: string } = {}
|
|
90
|
+
): string {
|
|
91
|
+
const {
|
|
92
|
+
separator = ' ',
|
|
93
|
+
keyColor = '#888888',
|
|
94
|
+
valueColor = '#00ffff'
|
|
95
|
+
} = options;
|
|
96
|
+
|
|
97
|
+
const entries = Object.entries(obj);
|
|
98
|
+
if (entries.length === 0) return '';
|
|
99
|
+
|
|
100
|
+
const keyColorCode = colorCapability !== 'none'
|
|
101
|
+
? getANSIForeground(keyColor, colorCapability)
|
|
102
|
+
: '';
|
|
103
|
+
const valueColorCode = colorCapability !== 'none'
|
|
104
|
+
? getANSIForeground(valueColor, colorCapability)
|
|
105
|
+
: '';
|
|
106
|
+
const reset = colorCapability !== 'none' ? ANSI.reset : '';
|
|
107
|
+
|
|
108
|
+
return entries
|
|
109
|
+
.map(([key, value]) => {
|
|
110
|
+
const valueStr = typeof value === 'object'
|
|
111
|
+
? JSON.stringify(value)
|
|
112
|
+
: String(value);
|
|
113
|
+
return `${keyColorCode}${key}:${reset} ${valueColorCode}${valueStr}${reset}`;
|
|
114
|
+
})
|
|
115
|
+
.join(separator);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function isKeyValueObject(obj: unknown): obj is Record<string, unknown> {
|
|
119
|
+
if (typeof obj !== 'object' || obj === null) return false;
|
|
120
|
+
if (Array.isArray(obj)) return false;
|
|
121
|
+
|
|
122
|
+
const proto = Object.getPrototypeOf(obj);
|
|
123
|
+
if (proto !== Object.prototype && proto !== null) return false;
|
|
124
|
+
|
|
125
|
+
const values = Object.values(obj);
|
|
126
|
+
return values.every(v =>
|
|
127
|
+
typeof v === 'string' ||
|
|
128
|
+
typeof v === 'number' ||
|
|
129
|
+
typeof v === 'boolean' ||
|
|
130
|
+
v === null
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function formatBadge(
|
|
135
|
+
badge: string,
|
|
136
|
+
style: BadgeStyle = 'brackets',
|
|
137
|
+
colorCapability: ColorCapability = 'full',
|
|
138
|
+
color?: string
|
|
139
|
+
): string {
|
|
140
|
+
const colorCode = color && colorCapability !== 'none'
|
|
141
|
+
? getANSIForeground(color, colorCapability)
|
|
142
|
+
: '';
|
|
143
|
+
const reset = colorCapability !== 'none' ? ANSI.reset : '';
|
|
144
|
+
const bgBlack = colorCapability !== 'none' ? ANSI.bg.black : '';
|
|
145
|
+
|
|
146
|
+
const text = badge.toUpperCase();
|
|
147
|
+
|
|
148
|
+
switch (style) {
|
|
149
|
+
case 'rounded':
|
|
150
|
+
return `${bgBlack}${colorCode}⟨${text}⟩${reset}`;
|
|
151
|
+
case 'plain':
|
|
152
|
+
return `${colorCode}${text}${reset}`;
|
|
153
|
+
case 'unicode':
|
|
154
|
+
return `${bgBlack}${colorCode}╭${text}╮${reset}`;
|
|
155
|
+
case 'pill':
|
|
156
|
+
return `${bgBlack}${colorCode}⦗${text}⦘${reset}`;
|
|
157
|
+
case 'brackets':
|
|
158
|
+
default:
|
|
159
|
+
return `${bgBlack}${colorCode}[${text}]${reset}`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function formatTimestamp(
|
|
164
|
+
date: Date = new Date(),
|
|
165
|
+
format: TimestampFormat = 'time'
|
|
166
|
+
): string {
|
|
167
|
+
switch (format) {
|
|
168
|
+
case 'iso':
|
|
169
|
+
return date.toISOString();
|
|
170
|
+
case 'date':
|
|
171
|
+
return date.toISOString().split('T')[0] ?? '';
|
|
172
|
+
case 'time':
|
|
173
|
+
return date.toTimeString().slice(0, 8);
|
|
174
|
+
case 'timeMs':
|
|
175
|
+
return date.toTimeString().slice(0, 8) + '.' +
|
|
176
|
+
String(date.getMilliseconds()).padStart(3, '0');
|
|
177
|
+
case 'relative':
|
|
178
|
+
return formatRelativeTime(date);
|
|
179
|
+
case 'elapsed':
|
|
180
|
+
return formatElapsedTime(date);
|
|
181
|
+
case 'custom':
|
|
182
|
+
default:
|
|
183
|
+
return date.toLocaleTimeString();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let startTime: number | null = null;
|
|
188
|
+
|
|
189
|
+
export function formatRelativeTime(date: Date): string {
|
|
190
|
+
if (startTime === null) {
|
|
191
|
+
startTime = Date.now();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const diff = date.getTime() - startTime;
|
|
195
|
+
|
|
196
|
+
if (diff < 1000) {
|
|
197
|
+
return `+${diff}ms`;
|
|
198
|
+
} else if (diff < 60000) {
|
|
199
|
+
return `+${(diff / 1000).toFixed(1)}s`;
|
|
200
|
+
} else {
|
|
201
|
+
const mins = Math.floor(diff / 60000);
|
|
202
|
+
const secs = Math.floor((diff % 60000) / 1000);
|
|
203
|
+
return `+${mins}m${secs}s`;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function formatElapsedTime(date: Date): string {
|
|
208
|
+
if (startTime === null) {
|
|
209
|
+
startTime = Date.now();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const diff = date.getTime() - startTime;
|
|
213
|
+
const hours = Math.floor(diff / 3600000);
|
|
214
|
+
const mins = Math.floor((diff % 3600000) / 60000);
|
|
215
|
+
const secs = Math.floor((diff % 60000) / 1000);
|
|
216
|
+
|
|
217
|
+
return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function resetStartTime(): void {
|
|
221
|
+
startTime = Date.now();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function applyLogOptions(
|
|
225
|
+
message: string,
|
|
226
|
+
options: LogOptions,
|
|
227
|
+
colorCapability: ColorCapability = 'full'
|
|
228
|
+
): string {
|
|
229
|
+
let result = message;
|
|
230
|
+
|
|
231
|
+
if (options.rightAlign) {
|
|
232
|
+
result = formatWithRightAlign(message, options.rightAlign);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { LogLevel } from '../types/index.js';
|
|
7
7
|
import type { LogStyles } from '../types/index.js';
|
|
8
|
+
import { getANSIForeground, getANSIBackground, ANSI, type ColorCapability } from './color-converter.js';
|
|
8
9
|
|
|
9
10
|
export type ANSIStyle = {
|
|
10
11
|
text: string;
|
|
@@ -17,32 +18,19 @@ export type ANSIStyle = {
|
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
export class TerminalRenderer {
|
|
20
|
-
private colorCapability:
|
|
21
|
+
private colorCapability: ColorCapability;
|
|
21
22
|
|
|
22
|
-
constructor(colorCapability:
|
|
23
|
+
constructor(colorCapability: ColorCapability = 'full') {
|
|
23
24
|
this.colorCapability = colorCapability;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* Get ANSI color codes
|
|
28
|
+
* Get ANSI color codes - now supports truecolor/256-color
|
|
28
29
|
*/
|
|
29
30
|
private getColorCode(color: string, background: boolean = false): string {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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`;
|
|
31
|
+
return background
|
|
32
|
+
? getANSIBackground(color, this.colorCapability)
|
|
33
|
+
: getANSIForeground(color, this.colorCapability);
|
|
46
34
|
}
|
|
47
35
|
|
|
48
36
|
/**
|
|
@@ -207,7 +195,7 @@ export class TerminalRenderer {
|
|
|
207
195
|
}
|
|
208
196
|
|
|
209
197
|
/**
|
|
210
|
-
* Create cyberpunk-style ANSI rendering
|
|
198
|
+
* Create cyberpunk-style ANSI rendering with truecolor support
|
|
211
199
|
*/
|
|
212
200
|
renderCyberpunk(
|
|
213
201
|
level: LogLevel,
|
|
@@ -216,35 +204,36 @@ export class TerminalRenderer {
|
|
|
216
204
|
prefix?: string,
|
|
217
205
|
location?: string
|
|
218
206
|
): ANSIStyle {
|
|
219
|
-
const reset =
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
'
|
|
223
|
-
'
|
|
224
|
-
'
|
|
225
|
-
'
|
|
207
|
+
const reset = ANSI.reset;
|
|
208
|
+
|
|
209
|
+
const cyberpunkColors: Record<LogLevel, string> = {
|
|
210
|
+
'debug': '#ff00ff', // Neon magenta
|
|
211
|
+
'info': '#00ffff', // Neon cyan
|
|
212
|
+
'warn': '#ffff00', // Neon yellow
|
|
213
|
+
'error': '#ff0040', // Neon red-pink
|
|
214
|
+
'critical': '#ff0000' // Pure red
|
|
226
215
|
};
|
|
227
216
|
|
|
228
217
|
const parts: string[] = [];
|
|
229
218
|
|
|
230
219
|
if (timestamp) {
|
|
231
|
-
parts.push(
|
|
220
|
+
parts.push(`${ANSI.dim}${timestamp}${reset}`);
|
|
232
221
|
}
|
|
233
222
|
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
parts.push(`${bgBlack}${levelColor} ${this.getLevelText(level)} ${reset}`);
|
|
223
|
+
const levelColor = this.getColorCode(cyberpunkColors[level] || '#ffffff');
|
|
224
|
+
const bgBlack = ANSI.bg.black;
|
|
225
|
+
const bold = level === 'critical' ? ANSI.bold : '';
|
|
226
|
+
parts.push(`${bgBlack}${levelColor}${bold} ${this.getLevelText(level)} ${reset}`);
|
|
238
227
|
|
|
239
228
|
if (prefix) {
|
|
240
|
-
const
|
|
241
|
-
parts.push(`${bgBlack}
|
|
229
|
+
const cyanColor = this.getColorCode('#00ffff');
|
|
230
|
+
parts.push(`${bgBlack}${cyanColor}[${prefix.toUpperCase()}]${reset}`);
|
|
242
231
|
}
|
|
243
232
|
|
|
244
233
|
parts.push(message);
|
|
245
234
|
|
|
246
235
|
if (location) {
|
|
247
|
-
parts.push(
|
|
236
|
+
parts.push(`${ANSI.dim}(${location})${reset}`);
|
|
248
237
|
}
|
|
249
238
|
|
|
250
239
|
return {
|
|
@@ -254,7 +243,7 @@ export class TerminalRenderer {
|
|
|
254
243
|
}
|
|
255
244
|
|
|
256
245
|
/**
|
|
257
|
-
* Create minimal ANSI rendering
|
|
246
|
+
* Create minimal ANSI rendering with truecolor support
|
|
258
247
|
*/
|
|
259
248
|
renderMinimal(
|
|
260
249
|
level: LogLevel,
|
|
@@ -262,26 +251,29 @@ export class TerminalRenderer {
|
|
|
262
251
|
timestamp?: string,
|
|
263
252
|
prefix?: string
|
|
264
253
|
): ANSIStyle {
|
|
265
|
-
const reset =
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
'
|
|
269
|
-
'
|
|
270
|
-
'
|
|
271
|
-
'
|
|
254
|
+
const reset = ANSI.reset;
|
|
255
|
+
|
|
256
|
+
const minimalColors: Record<LogLevel, string> = {
|
|
257
|
+
'debug': '#c678dd', // Soft purple
|
|
258
|
+
'info': '#61afef', // Soft blue
|
|
259
|
+
'warn': '#e5c07b', // Soft yellow
|
|
260
|
+
'error': '#e06c75', // Soft red
|
|
261
|
+
'critical': '#be5046' // Dark red
|
|
272
262
|
};
|
|
273
263
|
|
|
274
264
|
const parts: string[] = [];
|
|
275
265
|
|
|
276
266
|
if (timestamp) {
|
|
277
|
-
parts.push(
|
|
267
|
+
parts.push(`${ANSI.dim}${timestamp}${reset}`);
|
|
278
268
|
}
|
|
279
269
|
|
|
280
|
-
const levelColor =
|
|
281
|
-
|
|
270
|
+
const levelColor = this.getColorCode(minimalColors[level] || '#abb2bf');
|
|
271
|
+
const bold = level === 'critical' ? ANSI.bold : '';
|
|
272
|
+
parts.push(`${levelColor}${bold}${this.getLevelText(level)}:${reset}`);
|
|
282
273
|
|
|
283
274
|
if (prefix) {
|
|
284
|
-
|
|
275
|
+
const cyanColor = this.getColorCode('#56b6c2');
|
|
276
|
+
parts.push(`${cyanColor}[${prefix.toUpperCase()}]${reset}`);
|
|
285
277
|
}
|
|
286
278
|
|
|
287
279
|
parts.push(message);
|
|
@@ -293,55 +285,58 @@ export class TerminalRenderer {
|
|
|
293
285
|
}
|
|
294
286
|
|
|
295
287
|
/**
|
|
296
|
-
* Get chalk
|
|
288
|
+
* Get chalk-like interface for log level with truecolor support
|
|
297
289
|
*/
|
|
298
|
-
public getChalkForLevel(level: LogLevel):
|
|
290
|
+
public getChalkForLevel(level: LogLevel): ChalkLikeInterface {
|
|
299
291
|
const levelColors: Record<LogLevel, string> = {
|
|
300
|
-
'debug': '
|
|
301
|
-
'info': '
|
|
302
|
-
'warn': '
|
|
303
|
-
'error': '
|
|
304
|
-
'critical': '
|
|
292
|
+
'debug': '#c678dd',
|
|
293
|
+
'info': '#61afef',
|
|
294
|
+
'warn': '#e5c07b',
|
|
295
|
+
'error': '#e06c75',
|
|
296
|
+
'critical': '#be5046'
|
|
305
297
|
};
|
|
306
298
|
|
|
299
|
+
const reset = ANSI.reset;
|
|
300
|
+
|
|
307
301
|
return {
|
|
308
302
|
color: (text: string) => {
|
|
309
|
-
const color = levelColors[level] || '
|
|
303
|
+
const color = levelColors[level] || '#abb2bf';
|
|
310
304
|
const colorCode = this.getColorCode(color);
|
|
311
|
-
return `${colorCode}${text}${
|
|
312
|
-
},
|
|
313
|
-
bold: (text: string) => {
|
|
314
|
-
const boldStyle = this.getStyleCode(['bold']);
|
|
315
|
-
return `${boldStyle}${text}${'\x1b[0m'}`;
|
|
316
|
-
},
|
|
317
|
-
dim: (text: string) => {
|
|
318
|
-
const dimStyle = this.getStyleCode(['dim']);
|
|
319
|
-
return `${dimStyle}${text}${'\x1b[0m'}`;
|
|
320
|
-
},
|
|
321
|
-
bgGray: (text: string) => {
|
|
322
|
-
return `\x1b[100m${text}${'\x1b[0m'}`;
|
|
323
|
-
},
|
|
324
|
-
bgBlue: (text: string) => {
|
|
325
|
-
return `\x1b[104m${text}${'\x1b[0m'}`;
|
|
305
|
+
return `${colorCode}${text}${reset}`;
|
|
326
306
|
},
|
|
307
|
+
bold: (text: string) => `${ANSI.bold}${text}${reset}`,
|
|
308
|
+
dim: (text: string) => `${ANSI.dim}${text}${reset}`,
|
|
309
|
+
bgGray: (text: string) => `${ANSI.bg.gray}${text}${reset}`,
|
|
310
|
+
bgBlue: (text: string) => `${this.getColorCode('#1e3a5f', true)}${text}${reset}`,
|
|
327
311
|
reset: (text: string) => text,
|
|
328
312
|
cyan: {
|
|
329
313
|
bold: (text: string) => {
|
|
330
|
-
const cyan = this.getColorCode('
|
|
331
|
-
|
|
332
|
-
return `${cyan}${bold}${text}${'\x1b[0m'}`;
|
|
314
|
+
const cyan = this.getColorCode('#00ffff');
|
|
315
|
+
return `${cyan}${ANSI.bold}${text}${reset}`;
|
|
333
316
|
},
|
|
334
317
|
dim: (text: string) => {
|
|
335
|
-
const cyan = this.getColorCode('
|
|
336
|
-
|
|
337
|
-
return `${cyan}${dim}${text}${'\x1b[0m'}`;
|
|
318
|
+
const cyan = this.getColorCode('#00ffff');
|
|
319
|
+
return `${cyan}${ANSI.dim}${text}${reset}`;
|
|
338
320
|
},
|
|
339
321
|
bg: (text: string) => {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
return `${bgBlack}${cyan}[${text.toUpperCase()}]${'\x1b[0m'}`;
|
|
322
|
+
const cyan = this.getColorCode('#00ffff');
|
|
323
|
+
return `${ANSI.bg.black}${cyan}[${text.toUpperCase()}]${reset}`;
|
|
343
324
|
}
|
|
344
325
|
}
|
|
345
326
|
};
|
|
346
327
|
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export interface ChalkLikeInterface {
|
|
331
|
+
color: (text: string) => string;
|
|
332
|
+
bold: (text: string) => string;
|
|
333
|
+
dim: (text: string) => string;
|
|
334
|
+
bgGray: (text: string) => string;
|
|
335
|
+
bgBlue: (text: string) => string;
|
|
336
|
+
reset: (text: string) => string;
|
|
337
|
+
cyan: {
|
|
338
|
+
bold: (text: string) => string;
|
|
339
|
+
dim: (text: string) => string;
|
|
340
|
+
bg: (text: string) => string;
|
|
341
|
+
};
|
|
347
342
|
}
|
package/src/types/core.ts
CHANGED
|
@@ -100,6 +100,48 @@ export type ExportFormat = 'json' | 'csv' | 'markdown' | 'plain' | 'html';
|
|
|
100
100
|
*/
|
|
101
101
|
export type OutputFormat = 'auto' | 'plain' | 'ansi' | 'build' | 'ci';
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Output modes for controlling where logs are written
|
|
105
|
+
* @typedef {'console' | 'silent' | 'custom'} OutputMode
|
|
106
|
+
*
|
|
107
|
+
* @description
|
|
108
|
+
* - console: Standard console.log output (default)
|
|
109
|
+
* - silent: No output at all
|
|
110
|
+
* - custom: Use custom OutputWriter for advanced scenarios
|
|
111
|
+
*/
|
|
112
|
+
export type OutputMode = 'console' | 'silent' | 'custom';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Custom output writer interface for redirecting log output
|
|
116
|
+
*
|
|
117
|
+
* @interface OutputWriter
|
|
118
|
+
* @since 4.0.0
|
|
119
|
+
*
|
|
120
|
+
* @description
|
|
121
|
+
* Allows redirecting log output to custom destinations like:
|
|
122
|
+
* - DraftLog for CLI spinners with concurrent logging
|
|
123
|
+
* - Buffers for collecting logs during operations
|
|
124
|
+
* - Custom streams or transports
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* class BufferWriter implements OutputWriter {
|
|
128
|
+
* private buffer: string[] = [];
|
|
129
|
+
*
|
|
130
|
+
* write(message: string, level: LogLevel, styles: string[]): void {
|
|
131
|
+
* this.buffer.push(message);
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* flush(): void {
|
|
135
|
+
* this.buffer.forEach(msg => console.log(msg));
|
|
136
|
+
* this.buffer = [];
|
|
137
|
+
* }
|
|
138
|
+
* }
|
|
139
|
+
*/
|
|
140
|
+
export interface OutputWriter {
|
|
141
|
+
write(message: string, level: LogLevel, styles: string[]): void;
|
|
142
|
+
flush?(): void;
|
|
143
|
+
}
|
|
144
|
+
|
|
103
145
|
/**
|
|
104
146
|
* Interfaz de configuración para instancias del logger
|
|
105
147
|
*
|
|
@@ -130,6 +172,10 @@ export interface LoggerConfig {
|
|
|
130
172
|
bufferSize?: number;
|
|
131
173
|
autoDetectTheme?: boolean;
|
|
132
174
|
outputFormat?: OutputFormat;
|
|
175
|
+
/** Output mode: 'console' (default), 'silent', or 'custom' @since 4.0.0 */
|
|
176
|
+
outputMode?: OutputMode;
|
|
177
|
+
/** Custom writer when outputMode is 'custom' @since 4.0.0 */
|
|
178
|
+
outputWriter?: OutputWriter;
|
|
133
179
|
}
|
|
134
180
|
|
|
135
181
|
/**
|
|
@@ -293,4 +339,26 @@ export interface Bindings {
|
|
|
293
339
|
badges?: string[];
|
|
294
340
|
type?: 'scope' | 'api' | 'component';
|
|
295
341
|
context?: string[];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export type BadgeStyle = 'brackets' | 'rounded' | 'plain' | 'unicode' | 'pill';
|
|
345
|
+
|
|
346
|
+
export type TimestampFormat = 'iso' | 'time' | 'timeMs' | 'relative' | 'elapsed' | 'date' | 'custom';
|
|
347
|
+
|
|
348
|
+
export type ColumnAlign = 'left' | 'right' | 'center';
|
|
349
|
+
|
|
350
|
+
export interface ColumnConfig {
|
|
351
|
+
content: string;
|
|
352
|
+
width?: number;
|
|
353
|
+
align?: ColumnAlign;
|
|
354
|
+
color?: string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export interface LogOptions {
|
|
358
|
+
rightAlign?: string;
|
|
359
|
+
columns?: ColumnConfig[];
|
|
360
|
+
maxWidth?: number;
|
|
361
|
+
keyValue?: boolean;
|
|
362
|
+
badgeStyle?: BadgeStyle;
|
|
363
|
+
timestampFormat?: TimestampFormat;
|
|
296
364
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -131,6 +131,26 @@ export function getColorCapability(): 'full' | 'basic' | 'none' {
|
|
|
131
131
|
return 'basic'; // Basic 16 colors
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Get terminal width in columns
|
|
136
|
+
*/
|
|
137
|
+
export function getTerminalWidth(): number {
|
|
138
|
+
if (typeof process !== 'undefined' && process.stdout?.columns) {
|
|
139
|
+
return process.stdout.columns;
|
|
140
|
+
}
|
|
141
|
+
return 80;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get terminal height in rows
|
|
146
|
+
*/
|
|
147
|
+
export function getTerminalHeight(): number {
|
|
148
|
+
if (typeof process !== 'undefined' && process.stdout?.rows) {
|
|
149
|
+
return process.stdout.rows;
|
|
150
|
+
}
|
|
151
|
+
return 24;
|
|
152
|
+
}
|
|
153
|
+
|
|
134
154
|
/**
|
|
135
155
|
* Environment information for debugging
|
|
136
156
|
*/
|
|
@@ -143,6 +163,8 @@ export function getEnvironmentInfo() {
|
|
|
143
163
|
platform: typeof process !== 'undefined' ? process.platform : 'unknown',
|
|
144
164
|
nodeVersion: typeof process !== 'undefined' ? process.versions?.node : null,
|
|
145
165
|
term: typeof process !== 'undefined' ? process.env?.TERM : null,
|
|
146
|
-
colorTerm: typeof process !== 'undefined' ? process.env?.COLORTERM : null
|
|
166
|
+
colorTerm: typeof process !== 'undefined' ? process.env?.COLORTERM : null,
|
|
167
|
+
terminalWidth: getTerminalWidth(),
|
|
168
|
+
terminalHeight: getTerminalHeight()
|
|
147
169
|
};
|
|
148
170
|
}
|