@mks2508/better-logger 1.0.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 +5 -3
- package/CHANGELOG.md +63 -0
- package/bun.lock +10 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/ScopedLogger.d.ts.map +1 -0
- package/dist/chunks/{Logger-CTAaDeZi.js → Logger-BynuRJQf.js} +12 -6
- package/dist/chunks/Logger-BynuRJQf.js.map +1 -0
- package/dist/chunks/{Logger-D8pK7XXt.js → Logger-DMjlVQWi.js} +2 -2
- package/dist/chunks/Logger-DMjlVQWi.js.map +1 -0
- package/dist/chunks/{ScopedLogger-hS0qSkZD.js → ScopedLogger-Bl56WovH.js} +2 -2
- package/dist/chunks/{ScopedLogger-hS0qSkZD.js.map → ScopedLogger-Bl56WovH.js.map} +1 -1
- package/dist/chunks/{ScopedLogger-D-7q8uVP.js → ScopedLogger-D2HzayKH.js} +2 -2
- package/dist/chunks/{ScopedLogger-D-7q8uVP.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-BanAyF-K.js +1172 -0
- package/dist/chunks/environment-BanAyF-K.js.map +1 -0
- package/dist/chunks/formatting-BSNvAxLK.js +2 -0
- package/dist/chunks/formatting-BSNvAxLK.js.map +1 -0
- package/dist/chunks/formatting-CgQSWgXR.js +380 -0
- package/dist/chunks/formatting-CgQSWgXR.js.map +1 -0
- package/dist/cli/CommandProcessor.d.ts.map +1 -0
- package/dist/cli/commands/ConfigCommand.d.ts.map +1 -0
- package/dist/cli/commands/ExportCommand.d.ts.map +1 -0
- package/dist/cli/commands/HistoryCommand.d.ts.map +1 -0
- package/dist/cli/commands/StatusCommand.d.ts.map +1 -0
- package/dist/cli/commands/ThemeCommand.d.ts.map +1 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{types/constants.d.ts → constants.d.ts} +108 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +127 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +6 -5
- package/dist/core.js.map +1 -1
- package/dist/example.d.ts.map +1 -0
- package/dist/exports-module.d.ts.map +1 -0
- package/dist/exports.cjs +1 -1
- package/dist/exports.js +2 -2
- package/dist/handlers/AnalyticsLogHandler.d.ts.map +1 -0
- package/dist/handlers/ExportLogHandler.d.ts.map +1 -0
- package/dist/handlers/FileLogHandler.d.ts.map +1 -0
- package/dist/handlers/RemoteLogHandler.d.ts.map +1 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +124 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -5
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -0
- package/dist/styling/LogStyleBuilder.d.ts.map +1 -0
- package/dist/styling/SemanticStyles.d.ts.map +1 -0
- package/dist/styling/SmartPresets.d.ts.map +1 -0
- package/dist/styling/StyleBuilder.d.ts.map +1 -0
- package/dist/styling/banners.d.ts.map +1 -0
- package/dist/styling/index.d.ts.map +1 -0
- package/dist/styling/themes.d.ts.map +1 -0
- package/dist/styling-module.d.ts.map +1 -0
- 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/types/core.d.ts +229 -122
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/handlers.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -119
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/adapter.d.ts +48 -0
- package/dist/utils/adapter.d.ts.map +1 -0
- package/dist/utils/ansi-colors.d.ts +156 -0
- package/dist/utils/ansi-colors.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/{types/utils → utils}/environment.d.ts +1 -1
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/{types/utils → utils}/formatting.d.ts +22 -1
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/{types/utils → utils}/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/opentui-detection.d.ts.map +1 -0
- package/dist/{types/utils → utils}/output.d.ts +7 -2
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/stackTrace.d.ts.map +1 -0
- package/dist/utils/timestamps.d.ts.map +1 -0
- package/package.json +10 -2
- package/src/Logger.ts +24 -19
- package/src/constants.ts +131 -1
- package/src/core.ts +11 -7
- package/src/handlers/ExportLogHandler.ts +2 -1
- package/src/index.ts +30 -2
- package/src/styling/SemanticStyles.ts +1 -1
- package/src/terminal/terminal-renderer.ts +339 -0
- package/src/types/core.ts +15 -1
- package/src/types/index.ts +1 -0
- package/src/utils/adapter.ts +291 -0
- package/src/utils/ansi-colors.ts +333 -0
- package/src/utils/environment-detector.ts +148 -0
- package/src/utils/formatting.ts +196 -6
- package/src/utils/index.ts +23 -11
- package/src/utils/output.ts +43 -1
- package/vite.config.ts +1 -1
- package/dist/chunks/Logger-CTAaDeZi.js.map +0 -1
- package/dist/chunks/Logger-D8pK7XXt.js.map +0 -1
- package/dist/chunks/environment-Bxbnw4pd.js +0 -544
- package/dist/chunks/environment-Bxbnw4pd.js.map +0 -1
- package/dist/chunks/environment-Dm66zOML.js +0 -4
- package/dist/chunks/environment-Dm66zOML.js.map +0 -1
- package/dist/chunks/formatting-C0riPC5_.js +0 -95
- package/dist/chunks/formatting-C0riPC5_.js.map +0 -1
- package/dist/chunks/formatting-DNCAV66-.js +0 -2
- package/dist/chunks/formatting-DNCAV66-.js.map +0 -1
- package/dist/types/Logger.d.ts.map +0 -1
- package/dist/types/ScopedLogger.d.ts.map +0 -1
- package/dist/types/cli/CommandProcessor.d.ts.map +0 -1
- package/dist/types/cli/commands/ConfigCommand.d.ts.map +0 -1
- package/dist/types/cli/commands/ExportCommand.d.ts.map +0 -1
- package/dist/types/cli/commands/HistoryCommand.d.ts.map +0 -1
- package/dist/types/cli/commands/StatusCommand.d.ts.map +0 -1
- package/dist/types/cli/commands/ThemeCommand.d.ts.map +0 -1
- package/dist/types/cli/help.d.ts.map +0 -1
- package/dist/types/cli/index.d.ts.map +0 -1
- package/dist/types/constants.d.ts.map +0 -1
- package/dist/types/example.d.ts.map +0 -1
- package/dist/types/exports-module.d.ts.map +0 -1
- package/dist/types/handlers/AnalyticsLogHandler.d.ts.map +0 -1
- package/dist/types/handlers/ExportLogHandler.d.ts.map +0 -1
- package/dist/types/handlers/FileLogHandler.d.ts.map +0 -1
- package/dist/types/handlers/RemoteLogHandler.d.ts.map +0 -1
- package/dist/types/handlers/index.d.ts.map +0 -1
- package/dist/types/main.d.ts.map +0 -1
- package/dist/types/styling/LogStyleBuilder.d.ts.map +0 -1
- package/dist/types/styling/SemanticStyles.d.ts.map +0 -1
- package/dist/types/styling/SmartPresets.d.ts.map +0 -1
- package/dist/types/styling/StyleBuilder.d.ts.map +0 -1
- package/dist/types/styling/banners.d.ts.map +0 -1
- package/dist/types/styling/index.d.ts.map +0 -1
- package/dist/types/styling/themes.d.ts.map +0 -1
- package/dist/types/styling-module.d.ts.map +0 -1
- package/dist/types/types/core.d.ts +0 -221
- package/dist/types/types/core.d.ts.map +0 -1
- package/dist/types/types/handlers.d.ts.map +0 -1
- package/dist/types/types/index.d.ts +0 -7
- package/dist/types/types/index.d.ts.map +0 -1
- package/dist/types/utils/environment.d.ts.map +0 -1
- package/dist/types/utils/formatting.d.ts.map +0 -1
- package/dist/types/utils/index.d.ts.map +0 -1
- package/dist/types/utils/opentui-detection.d.ts.map +0 -1
- package/dist/types/utils/output.d.ts.map +0 -1
- package/dist/types/utils/stackTrace.d.ts.map +0 -1
- package/dist/types/utils/timestamps.d.ts.map +0 -1
- /package/dist/{types/Logger.d.ts → Logger.d.ts} +0 -0
- /package/dist/{types/ScopedLogger.d.ts → ScopedLogger.d.ts} +0 -0
- /package/dist/{types/cli → cli}/CommandProcessor.d.ts +0 -0
- /package/dist/{types/cli → cli}/commands/ConfigCommand.d.ts +0 -0
- /package/dist/{types/cli → cli}/commands/ExportCommand.d.ts +0 -0
- /package/dist/{types/cli → cli}/commands/HistoryCommand.d.ts +0 -0
- /package/dist/{types/cli → cli}/commands/StatusCommand.d.ts +0 -0
- /package/dist/{types/cli → cli}/commands/ThemeCommand.d.ts +0 -0
- /package/dist/{types/cli → cli}/help.d.ts +0 -0
- /package/dist/{types/cli → cli}/index.d.ts +0 -0
- /package/dist/{types/example.d.ts → example.d.ts} +0 -0
- /package/dist/{types/exports-module.d.ts → exports-module.d.ts} +0 -0
- /package/dist/{types/handlers → handlers}/AnalyticsLogHandler.d.ts +0 -0
- /package/dist/{types/handlers → handlers}/ExportLogHandler.d.ts +0 -0
- /package/dist/{types/handlers → handlers}/FileLogHandler.d.ts +0 -0
- /package/dist/{types/handlers → handlers}/RemoteLogHandler.d.ts +0 -0
- /package/dist/{types/handlers → handlers}/index.d.ts +0 -0
- /package/dist/{types/main.d.ts → main.d.ts} +0 -0
- /package/dist/{types/styling → styling}/LogStyleBuilder.d.ts +0 -0
- /package/dist/{types/styling → styling}/SemanticStyles.d.ts +0 -0
- /package/dist/{types/styling → styling}/SmartPresets.d.ts +0 -0
- /package/dist/{types/styling → styling}/StyleBuilder.d.ts +0 -0
- /package/dist/{types/styling → styling}/banners.d.ts +0 -0
- /package/dist/{types/styling → styling}/index.d.ts +0 -0
- /package/dist/{types/styling → styling}/themes.d.ts +0 -0
- /package/dist/{types/styling-module.d.ts → styling-module.d.ts} +0 -0
- /package/dist/types/{types/handlers.d.ts → handlers.d.ts} +0 -0
- /package/dist/{types/utils → utils}/opentui-detection.d.ts +0 -0
- /package/dist/{types/utils → utils}/stackTrace.d.ts +0 -0
- /package/dist/{types/utils → utils}/timestamps.d.ts +0 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ANSI color utilities for terminal environments
|
|
3
|
+
* @since 1.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { LogLevel } from '../types/index.js';
|
|
7
|
+
import { supportsANSIColors } from './environment.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* ANSI color codes for terminal styling
|
|
11
|
+
*/
|
|
12
|
+
export const ANSI_CODES = {
|
|
13
|
+
// Colors
|
|
14
|
+
black: 30,
|
|
15
|
+
red: 31,
|
|
16
|
+
green: 32,
|
|
17
|
+
yellow: 33,
|
|
18
|
+
blue: 34,
|
|
19
|
+
magenta: 35,
|
|
20
|
+
cyan: 36,
|
|
21
|
+
white: 37,
|
|
22
|
+
|
|
23
|
+
// Bright colors
|
|
24
|
+
brightBlack: 90,
|
|
25
|
+
brightRed: 91,
|
|
26
|
+
brightGreen: 92,
|
|
27
|
+
brightYellow: 93,
|
|
28
|
+
brightBlue: 94,
|
|
29
|
+
brightMagenta: 95,
|
|
30
|
+
brightCyan: 96,
|
|
31
|
+
brightWhite: 97,
|
|
32
|
+
|
|
33
|
+
// Background colors
|
|
34
|
+
bgBlack: 40,
|
|
35
|
+
bgRed: 41,
|
|
36
|
+
bgGreen: 42,
|
|
37
|
+
bgYellow: 43,
|
|
38
|
+
bgBlue: 44,
|
|
39
|
+
bgMagenta: 45,
|
|
40
|
+
bgCyan: 46,
|
|
41
|
+
bgWhite: 47,
|
|
42
|
+
|
|
43
|
+
// Background bright colors
|
|
44
|
+
bgBrightBlack: 100,
|
|
45
|
+
bgBrightRed: 101,
|
|
46
|
+
bgBrightGreen: 102,
|
|
47
|
+
bgBrightYellow: 103,
|
|
48
|
+
bgBrightBlue: 104,
|
|
49
|
+
bgBrightMagenta: 105,
|
|
50
|
+
bgBrightCyan: 106,
|
|
51
|
+
bgBrightWhite: 107,
|
|
52
|
+
|
|
53
|
+
// Styles
|
|
54
|
+
reset: 0,
|
|
55
|
+
bold: 1,
|
|
56
|
+
dim: 2,
|
|
57
|
+
italic: 3,
|
|
58
|
+
underline: 4,
|
|
59
|
+
blink: 5,
|
|
60
|
+
inverse: 7,
|
|
61
|
+
hidden: 8,
|
|
62
|
+
strikethrough: 9,
|
|
63
|
+
|
|
64
|
+
// Reset specific
|
|
65
|
+
resetBold: 22,
|
|
66
|
+
resetDim: 22,
|
|
67
|
+
resetItalic: 23,
|
|
68
|
+
resetUnderline: 24,
|
|
69
|
+
resetBlink: 25,
|
|
70
|
+
resetInverse: 27,
|
|
71
|
+
resetHidden: 28,
|
|
72
|
+
resetStrikethrough: 29
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* ANSI color presets for different log levels
|
|
77
|
+
*/
|
|
78
|
+
export const ANSI_LEVEL_STYLES: Record<LogLevel | 'success', {
|
|
79
|
+
color: number;
|
|
80
|
+
background?: number;
|
|
81
|
+
styles: number[];
|
|
82
|
+
emoji: string;
|
|
83
|
+
}> = {
|
|
84
|
+
debug: {
|
|
85
|
+
color: ANSI_CODES.brightBlack,
|
|
86
|
+
styles: [ANSI_CODES.dim],
|
|
87
|
+
emoji: '🔍'
|
|
88
|
+
},
|
|
89
|
+
info: {
|
|
90
|
+
color: ANSI_CODES.blue,
|
|
91
|
+
styles: [ANSI_CODES.bold],
|
|
92
|
+
emoji: 'ℹ️'
|
|
93
|
+
},
|
|
94
|
+
warn: {
|
|
95
|
+
color: ANSI_CODES.yellow,
|
|
96
|
+
background: ANSI_CODES.bgYellow,
|
|
97
|
+
styles: [ANSI_CODES.bold, ANSI_CODES.black],
|
|
98
|
+
emoji: '⚠️'
|
|
99
|
+
},
|
|
100
|
+
error: {
|
|
101
|
+
color: ANSI_CODES.red,
|
|
102
|
+
background: ANSI_CODES.bgRed,
|
|
103
|
+
styles: [ANSI_CODES.bold],
|
|
104
|
+
emoji: '❌'
|
|
105
|
+
},
|
|
106
|
+
critical: {
|
|
107
|
+
color: ANSI_CODES.white,
|
|
108
|
+
background: ANSI_CODES.bgRed,
|
|
109
|
+
styles: [ANSI_CODES.bold, ANSI_CODES.blink],
|
|
110
|
+
emoji: '🚨'
|
|
111
|
+
},
|
|
112
|
+
success: {
|
|
113
|
+
color: ANSI_CODES.green,
|
|
114
|
+
background: ANSI_CODES.bgGreen,
|
|
115
|
+
styles: [ANSI_CODES.bold],
|
|
116
|
+
emoji: '✅'
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Creates an ANSI escape sequence
|
|
122
|
+
*/
|
|
123
|
+
function ansi(code: number | number[]): string {
|
|
124
|
+
const codes = Array.isArray(code) ? code : [code];
|
|
125
|
+
return `\x1b[${codes.join(';')}m`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Applies ANSI styling to text
|
|
130
|
+
*/
|
|
131
|
+
export function ansiStyle(text: string, codes: number[]): string {
|
|
132
|
+
if (!supportsANSIColors()) return text;
|
|
133
|
+
return `${ansi(codes)}${text}${ansi(ANSI_CODES.reset)}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Applies color to text
|
|
138
|
+
*/
|
|
139
|
+
export function ansiColor(text: string, color: number): string {
|
|
140
|
+
return ansiStyle(text, [color]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Applies background color to text
|
|
145
|
+
*/
|
|
146
|
+
export function ansiBackground(text: string, bg: number, color?: number): string {
|
|
147
|
+
if (color) {
|
|
148
|
+
return ansiStyle(text, [color, bg]);
|
|
149
|
+
}
|
|
150
|
+
return ansiStyle(text, [bg]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Makes text bold
|
|
155
|
+
*/
|
|
156
|
+
export function ansiBold(text: string): string {
|
|
157
|
+
return ansiStyle(text, [ANSI_CODES.bold]);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Makes text dim
|
|
162
|
+
*/
|
|
163
|
+
export function ansiDim(text: string): string {
|
|
164
|
+
return ansiStyle(text, [ANSI_CODES.dim]);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Underlines text
|
|
169
|
+
*/
|
|
170
|
+
export function ansiUnderline(text: string): string {
|
|
171
|
+
return ansiStyle(text, [ANSI_CODES.underline]);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Specialized formatters for different contexts
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Format timestamp for terminal
|
|
180
|
+
*/
|
|
181
|
+
export function formatTimestampANSI(timestamp: string): string {
|
|
182
|
+
return ansiColor(timestamp, ANSI_CODES.brightBlack);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Format log level for terminal
|
|
187
|
+
*/
|
|
188
|
+
export function formatLogLevelANSI(level: LogLevel, useEmojis: boolean = true): string {
|
|
189
|
+
const style = ANSI_LEVEL_STYLES[level];
|
|
190
|
+
const emoji = useEmojis ? style.emoji : '';
|
|
191
|
+
const label = level.toUpperCase().padEnd(8);
|
|
192
|
+
|
|
193
|
+
if (!supportsANSIColors()) {
|
|
194
|
+
return `${emoji} ${label}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let codes = [style.color, ...style.styles];
|
|
198
|
+
if (style.background) {
|
|
199
|
+
codes.push(style.background);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return ansiStyle(`${emoji} ${label}`, codes);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Format success message for terminal
|
|
207
|
+
*/
|
|
208
|
+
export function formatSuccessANSI(message: string, useEmojis: boolean = true): string {
|
|
209
|
+
const style = ANSI_LEVEL_STYLES.success;
|
|
210
|
+
const emoji = useEmojis ? style.emoji : '';
|
|
211
|
+
|
|
212
|
+
if (!supportsANSIColors()) {
|
|
213
|
+
return `${emoji} SUCCESS: ${message}`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const prefix = ansiStyle(`${emoji} SUCCESS:`, [style.color, ...style.styles]);
|
|
217
|
+
return `${prefix} ${message}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Format prefix for terminal
|
|
222
|
+
*/
|
|
223
|
+
export function formatPrefixANSI(prefix: string): string {
|
|
224
|
+
if (!supportsANSIColors()) {
|
|
225
|
+
return `[${prefix}]`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return ansiStyle(`[${prefix}]`, [ANSI_CODES.cyan, ANSI_CODES.bold]);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Format file location for terminal
|
|
233
|
+
*/
|
|
234
|
+
export function formatLocationANSI(location: string): string {
|
|
235
|
+
if (!supportsANSIColors()) {
|
|
236
|
+
return `(${location})`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return ansiColor(`(${location})`, ANSI_CODES.brightBlack);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Format build-specific messages
|
|
244
|
+
*/
|
|
245
|
+
export const BUILD_FORMATTERS = {
|
|
246
|
+
/**
|
|
247
|
+
* Format compilation step
|
|
248
|
+
*/
|
|
249
|
+
compilation: (step: string, status: 'starting' | 'completed' | 'failed' = 'starting') => {
|
|
250
|
+
const stepText = ansiBold(step);
|
|
251
|
+
|
|
252
|
+
switch (status) {
|
|
253
|
+
case 'starting':
|
|
254
|
+
return `${ansiColor('⚙️', ANSI_CODES.blue)} ${stepText}...`;
|
|
255
|
+
case 'completed':
|
|
256
|
+
return `${ansiColor('✓', ANSI_CODES.green)} ${stepText} ${ansiColor('completed', ANSI_CODES.green)}`;
|
|
257
|
+
case 'failed':
|
|
258
|
+
return `${ansiColor('✗', ANSI_CODES.red)} ${stepText} ${ansiColor('failed', ANSI_CODES.red)}`;
|
|
259
|
+
default:
|
|
260
|
+
return stepText;
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Format warning message
|
|
266
|
+
*/
|
|
267
|
+
warning: (message: string) => {
|
|
268
|
+
return `${ansiColor('⚠', ANSI_CODES.yellow)} ${ansiStyle('Warning:', [ANSI_CODES.yellow, ANSI_CODES.bold])} ${message}`;
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Format error message
|
|
273
|
+
*/
|
|
274
|
+
error: (message: string) => {
|
|
275
|
+
return `${ansiColor('✗', ANSI_CODES.red)} ${ansiStyle('Error:', [ANSI_CODES.red, ANSI_CODES.bold])} ${message}`;
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Format success message
|
|
280
|
+
*/
|
|
281
|
+
success: (message: string) => {
|
|
282
|
+
return `${ansiColor('✓', ANSI_CODES.green)} ${ansiColor(message, ANSI_CODES.green)}`;
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Format info message
|
|
287
|
+
*/
|
|
288
|
+
info: (message: string) => {
|
|
289
|
+
return `${ansiColor('ℹ', ANSI_CODES.blue)} ${message}`;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Terminal-friendly emoji alternatives for environments that don't support them
|
|
295
|
+
*/
|
|
296
|
+
export const EMOJI_ALTERNATIVES = {
|
|
297
|
+
'🔍': '[DEBUG]',
|
|
298
|
+
'ℹ️': '[INFO]',
|
|
299
|
+
'⚠️': '[WARN]',
|
|
300
|
+
'❌': '[ERROR]',
|
|
301
|
+
'🚨': '[CRITICAL]',
|
|
302
|
+
'✅': '[OK]',
|
|
303
|
+
'✓': '[OK]',
|
|
304
|
+
'✗': '[FAIL]',
|
|
305
|
+
'⚙️': '[BUILD]',
|
|
306
|
+
'📦': '[PKG]'
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Replace emojis with text alternatives for non-emoji terminals
|
|
311
|
+
*/
|
|
312
|
+
export function sanitizeEmojis(text: string): string {
|
|
313
|
+
// Check if we're in a terminal that likely supports emojis
|
|
314
|
+
const isModernTerminal = process.env.TERM &&
|
|
315
|
+
(process.env.TERM.includes('xterm') ||
|
|
316
|
+
process.env.TERM.includes('screen') ||
|
|
317
|
+
process.env.TERM.includes('tmux'));
|
|
318
|
+
|
|
319
|
+
const isCI = process.env.CI || process.env.GITHUB_ACTIONS || process.env.JENKINS_URL;
|
|
320
|
+
|
|
321
|
+
// Use emojis if we have a modern terminal and not in CI
|
|
322
|
+
if (isModernTerminal && !isCI) {
|
|
323
|
+
return text;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Replace emojis with text alternatives
|
|
327
|
+
let result = text;
|
|
328
|
+
Object.entries(EMOJI_ALTERNATIVES).forEach(([emoji, alt]) => {
|
|
329
|
+
result = result.replace(new RegExp(emoji, 'g'), alt);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Detector - Robust environment detection for logger
|
|
3
|
+
* Detects browser, terminal, server, and other runtime environments
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type Environment = 'browser' | 'terminal' | 'server' | 'webworker' | 'deno' | 'unknown';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Main environment detection function
|
|
10
|
+
*/
|
|
11
|
+
export function getEnvironment(): Environment {
|
|
12
|
+
// Check for Deno first
|
|
13
|
+
if (typeof globalThis !== 'undefined' && (globalThis as any).Deno) {
|
|
14
|
+
return 'deno';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check for WebWorker
|
|
18
|
+
if (typeof window === 'undefined' && typeof self !== 'undefined' && typeof (self as any).importScripts === 'function') {
|
|
19
|
+
return 'webworker';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check for Node.js (server environment)
|
|
23
|
+
if (typeof process !== 'undefined' && process.versions && process.versions.node) {
|
|
24
|
+
// Determine if it's running in a terminal or as a server
|
|
25
|
+
if (isRunningInTerminal()) {
|
|
26
|
+
return 'terminal';
|
|
27
|
+
}
|
|
28
|
+
return 'server';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check for browser
|
|
32
|
+
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
33
|
+
return 'browser';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return 'unknown';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if running in an interactive terminal
|
|
41
|
+
*/
|
|
42
|
+
export function isRunningInTerminal(): boolean {
|
|
43
|
+
// Check for common terminal indicators
|
|
44
|
+
if (typeof process === 'undefined') return false;
|
|
45
|
+
|
|
46
|
+
const isTTY = process.stdout && process.stdout.isTTY;
|
|
47
|
+
const hasTerminalEnv = process.env && (
|
|
48
|
+
process.env.TERM ||
|
|
49
|
+
process.env.TERM_PROGRAM ||
|
|
50
|
+
process.env.SSH_TTY ||
|
|
51
|
+
process.env.TERM_SESSION_ID
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Check if we're running in common terminal programs
|
|
55
|
+
const terminalPrograms = [
|
|
56
|
+
'vscode',
|
|
57
|
+
'hyper',
|
|
58
|
+
'iterm',
|
|
59
|
+
'terminal',
|
|
60
|
+
'alacritty',
|
|
61
|
+
'kitty',
|
|
62
|
+
'gnome-terminal',
|
|
63
|
+
'konsole',
|
|
64
|
+
'xterm',
|
|
65
|
+
'tmux',
|
|
66
|
+
'screen'
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const isTerminalProgram = hasTerminalEnv && terminalPrograms.some(program =>
|
|
70
|
+
process.env.TERM_PROGRAM?.toLowerCase().includes(program) ||
|
|
71
|
+
process.env.TERM?.toLowerCase().includes(program)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
return Boolean(isTTY || hasTerminalEnv || isTerminalProgram);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if environment supports ANSI colors
|
|
79
|
+
*/
|
|
80
|
+
export function supportsANSI(): boolean {
|
|
81
|
+
const env = getEnvironment();
|
|
82
|
+
|
|
83
|
+
if (env === 'browser') return false;
|
|
84
|
+
if (env === 'terminal') return true;
|
|
85
|
+
if (env === 'server') return checkServerANSISupport();
|
|
86
|
+
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Check if server environment supports ANSI colors
|
|
92
|
+
*/
|
|
93
|
+
function checkServerANSISupport(): boolean {
|
|
94
|
+
if (typeof process === 'undefined') return false;
|
|
95
|
+
|
|
96
|
+
// Check common environment variables that indicate ANSI support
|
|
97
|
+
const supportsANSI = process.env && (
|
|
98
|
+
process.env.COLORTERM ||
|
|
99
|
+
process.env.FORCE_COLOR ||
|
|
100
|
+
(process.env.TERM && process.env.TERM !== 'dumb') ||
|
|
101
|
+
process.env.TERM_PROGRAM
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
return Boolean(supportsANSI);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get environment-specific color capability
|
|
109
|
+
*/
|
|
110
|
+
export function getColorCapability(): 'full' | 'basic' | 'none' {
|
|
111
|
+
const env = getEnvironment();
|
|
112
|
+
|
|
113
|
+
if (env === 'browser') {
|
|
114
|
+
return 'full'; // CSS colors
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!supportsANSI()) {
|
|
118
|
+
return 'none';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check for 256-color or truecolor support
|
|
122
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
123
|
+
const hasTrueColor = process.env.COLORTERM === 'truecolor' || process.env.COLORTERM === '24bit';
|
|
124
|
+
const has256Colors = process.env.TERM && process.env.TERM.includes('256');
|
|
125
|
+
|
|
126
|
+
if (hasTrueColor || has256Colors) {
|
|
127
|
+
return 'full';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return 'basic'; // Basic 16 colors
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Environment information for debugging
|
|
136
|
+
*/
|
|
137
|
+
export function getEnvironmentInfo() {
|
|
138
|
+
return {
|
|
139
|
+
environment: getEnvironment(),
|
|
140
|
+
supportsANSI: supportsANSI(),
|
|
141
|
+
colorCapability: getColorCapability(),
|
|
142
|
+
isTTY: typeof process !== 'undefined' ? Boolean(process.stdout?.isTTY) : false,
|
|
143
|
+
platform: typeof process !== 'undefined' ? process.platform : 'unknown',
|
|
144
|
+
nodeVersion: typeof process !== 'undefined' ? process.versions?.node : null,
|
|
145
|
+
term: typeof process !== 'undefined' ? process.env?.TERM : null,
|
|
146
|
+
colorTerm: typeof process !== 'undefined' ? process.env?.COLORTERM : null
|
|
147
|
+
};
|
|
148
|
+
}
|
package/src/utils/formatting.ts
CHANGED
|
@@ -2,8 +2,45 @@
|
|
|
2
2
|
* @fileoverview Formatting utilities for Universal Logger
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { LogLevel, StackInfo } from '../types/index.js';
|
|
5
|
+
import type { LogLevel, StackInfo, OutputFormat } from '../types/index.js';
|
|
6
6
|
import { formatTimestamp } from './timestamps.js';
|
|
7
|
+
import { isNode, supportsANSIColors } from './environment.js';
|
|
8
|
+
import {
|
|
9
|
+
formatLogLevelANSI,
|
|
10
|
+
formatTimestampANSI,
|
|
11
|
+
formatPrefixANSI,
|
|
12
|
+
formatLocationANSI,
|
|
13
|
+
sanitizeEmojis,
|
|
14
|
+
BUILD_FORMATTERS
|
|
15
|
+
} from './ansi-colors.js';
|
|
16
|
+
|
|
17
|
+
// Re-export the type for convenience
|
|
18
|
+
export type { OutputFormat } from '../types/index.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates output based on environment and format preference
|
|
22
|
+
*/
|
|
23
|
+
export function createOutput(
|
|
24
|
+
level: LogLevel,
|
|
25
|
+
message: string,
|
|
26
|
+
prefix?: string,
|
|
27
|
+
stackInfo?: StackInfo | null,
|
|
28
|
+
format: OutputFormat = 'auto'
|
|
29
|
+
): string {
|
|
30
|
+
const detectedFormat = format === 'auto' ? detectOptimalFormat() : format;
|
|
31
|
+
|
|
32
|
+
switch (detectedFormat) {
|
|
33
|
+
case 'ansi':
|
|
34
|
+
return createANSIOutput(level, message, prefix, stackInfo);
|
|
35
|
+
case 'build':
|
|
36
|
+
return createBuildOutput(level, message, prefix, stackInfo);
|
|
37
|
+
case 'ci':
|
|
38
|
+
return createCIOutput(level, message, prefix, stackInfo);
|
|
39
|
+
case 'plain':
|
|
40
|
+
default:
|
|
41
|
+
return createPlainOutput(level, message, prefix, stackInfo);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
7
44
|
|
|
8
45
|
/**
|
|
9
46
|
* Creates plain text output for any environment
|
|
@@ -17,22 +54,175 @@ export function createPlainOutput(
|
|
|
17
54
|
): string {
|
|
18
55
|
const timestamp = formatTimestamp();
|
|
19
56
|
const timeStr = timestamp.slice(11, 23); // HH:MM:SS.mmm
|
|
20
|
-
|
|
57
|
+
|
|
21
58
|
let output = `[${timeStr}] [${level.toUpperCase()}]`;
|
|
22
|
-
|
|
59
|
+
|
|
23
60
|
if (prefix) {
|
|
24
61
|
output += ` [${prefix}]`;
|
|
25
62
|
}
|
|
26
|
-
|
|
63
|
+
|
|
27
64
|
output += ` ${message}`;
|
|
28
|
-
|
|
65
|
+
|
|
29
66
|
if (stackInfo) {
|
|
30
67
|
output += ` (${stackInfo.file}:${stackInfo.line}:${stackInfo.column})`;
|
|
31
68
|
}
|
|
32
|
-
|
|
69
|
+
|
|
33
70
|
return output;
|
|
34
71
|
}
|
|
35
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Creates ANSI-colored output for terminals
|
|
75
|
+
*/
|
|
76
|
+
export function createANSIOutput(
|
|
77
|
+
level: LogLevel,
|
|
78
|
+
message: string,
|
|
79
|
+
prefix?: string,
|
|
80
|
+
stackInfo?: StackInfo | null
|
|
81
|
+
): string {
|
|
82
|
+
const timestamp = formatTimestamp();
|
|
83
|
+
const timeStr = timestamp.slice(11, 23);
|
|
84
|
+
|
|
85
|
+
let output = '';
|
|
86
|
+
|
|
87
|
+
// Timestamp
|
|
88
|
+
output += formatTimestampANSI(`[${timeStr}]`) + ' ';
|
|
89
|
+
|
|
90
|
+
// Log level with colors
|
|
91
|
+
output += formatLogLevelANSI(level) + ' ';
|
|
92
|
+
|
|
93
|
+
// Prefix if provided
|
|
94
|
+
if (prefix) {
|
|
95
|
+
output += formatPrefixANSI(prefix) + ' ';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Message
|
|
99
|
+
output += message;
|
|
100
|
+
|
|
101
|
+
// Stack info if provided
|
|
102
|
+
if (stackInfo) {
|
|
103
|
+
output += ' ' + formatLocationANSI(`(${stackInfo.file}:${stackInfo.line}:${stackInfo.column})`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return sanitizeEmojis(output);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates build-friendly output (optimized for Next.js builds, webpack, etc.)
|
|
111
|
+
*/
|
|
112
|
+
export function createBuildOutput(
|
|
113
|
+
level: LogLevel,
|
|
114
|
+
message: string,
|
|
115
|
+
prefix?: string,
|
|
116
|
+
stackInfo?: StackInfo | null
|
|
117
|
+
): string {
|
|
118
|
+
const timestamp = formatTimestamp();
|
|
119
|
+
const timeStr = timestamp.slice(11, 23);
|
|
120
|
+
|
|
121
|
+
let output = '';
|
|
122
|
+
|
|
123
|
+
// Use ANSI colors if supported
|
|
124
|
+
if (supportsANSIColors()) {
|
|
125
|
+
output += formatTimestampANSI(`[${timeStr}]`) + ' ';
|
|
126
|
+
|
|
127
|
+
// Use build-specific formatters
|
|
128
|
+
switch (level) {
|
|
129
|
+
case 'info':
|
|
130
|
+
output += BUILD_FORMATTERS.info(message);
|
|
131
|
+
break;
|
|
132
|
+
case 'warn':
|
|
133
|
+
output += BUILD_FORMATTERS.warning(message);
|
|
134
|
+
break;
|
|
135
|
+
case 'error':
|
|
136
|
+
case 'critical':
|
|
137
|
+
output += BUILD_FORMATTERS.error(message);
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
output += `${formatLogLevelANSI(level)} ${message}`;
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
// Fallback to plain text
|
|
144
|
+
output = `[${timeStr}] [${level.toUpperCase()}]`;
|
|
145
|
+
|
|
146
|
+
if (prefix) {
|
|
147
|
+
output += ` [${prefix}]`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
output += ` ${message}`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (stackInfo) {
|
|
154
|
+
output += ` (${stackInfo.file}:${stackInfo.line}:${stackInfo.column})`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return sanitizeEmojis(output);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Creates CI-friendly output (no emojis, simple formatting)
|
|
162
|
+
*/
|
|
163
|
+
export function createCIOutput(
|
|
164
|
+
level: LogLevel,
|
|
165
|
+
message: string,
|
|
166
|
+
prefix?: string,
|
|
167
|
+
stackInfo?: StackInfo | null
|
|
168
|
+
): string {
|
|
169
|
+
const timestamp = formatTimestamp();
|
|
170
|
+
const timeStr = timestamp.slice(11, 23);
|
|
171
|
+
|
|
172
|
+
let output = `[${timeStr}] [${level.toUpperCase()}]`;
|
|
173
|
+
|
|
174
|
+
if (prefix) {
|
|
175
|
+
output += ` [${prefix}]`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
output += ` ${message}`;
|
|
179
|
+
|
|
180
|
+
if (stackInfo) {
|
|
181
|
+
output += ` (${stackInfo.file}:${stackInfo.line}:${stackInfo.column})`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Always remove emojis for CI
|
|
185
|
+
return sanitizeEmojis(output);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Detects the optimal output format based on environment
|
|
190
|
+
*/
|
|
191
|
+
export function detectOptimalFormat(): OutputFormat {
|
|
192
|
+
// Check for specific environment variables
|
|
193
|
+
const isCI = process.env.CI ||
|
|
194
|
+
process.env.GITHUB_ACTIONS ||
|
|
195
|
+
process.env.JENKINS_URL ||
|
|
196
|
+
process.env.GITLAB_CI ||
|
|
197
|
+
process.env.TRAVIS ||
|
|
198
|
+
process.env.CIRCLECI;
|
|
199
|
+
|
|
200
|
+
const isBuild = process.env.NODE_ENV === 'production' ||
|
|
201
|
+
process.env.BUILD_MODE === 'production' ||
|
|
202
|
+
process.argv.some(arg => arg.includes('build') || arg.includes('webpack'));
|
|
203
|
+
|
|
204
|
+
const isNextJS = process.env.NEXT_RUNTIME ||
|
|
205
|
+
process.argv.some(arg => arg.includes('next'));
|
|
206
|
+
|
|
207
|
+
// CI environment - always use plain text
|
|
208
|
+
if (isCI) {
|
|
209
|
+
return 'ci';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Next.js build environment
|
|
213
|
+
if (isNextJS || isBuild) {
|
|
214
|
+
return 'build';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Node.js with ANSI support
|
|
218
|
+
if (isNode && supportsANSIColors()) {
|
|
219
|
+
return 'ansi';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Default to plain text
|
|
223
|
+
return 'plain';
|
|
224
|
+
}
|
|
225
|
+
|
|
36
226
|
/**
|
|
37
227
|
* Gets the appropriate log method for the level
|
|
38
228
|
* Uses different console methods for better semantics
|