@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.
Files changed (183) hide show
  1. package/.claude/settings.local.json +5 -3
  2. package/CHANGELOG.md +63 -0
  3. package/bun.lock +10 -0
  4. package/dist/Logger.d.ts.map +1 -0
  5. package/dist/ScopedLogger.d.ts.map +1 -0
  6. package/dist/chunks/{Logger-CTAaDeZi.js → Logger-BynuRJQf.js} +12 -6
  7. package/dist/chunks/Logger-BynuRJQf.js.map +1 -0
  8. package/dist/chunks/{Logger-D8pK7XXt.js → Logger-DMjlVQWi.js} +2 -2
  9. package/dist/chunks/Logger-DMjlVQWi.js.map +1 -0
  10. package/dist/chunks/{ScopedLogger-hS0qSkZD.js → ScopedLogger-Bl56WovH.js} +2 -2
  11. package/dist/chunks/{ScopedLogger-hS0qSkZD.js.map → ScopedLogger-Bl56WovH.js.map} +1 -1
  12. package/dist/chunks/{ScopedLogger-D-7q8uVP.js → ScopedLogger-D2HzayKH.js} +2 -2
  13. package/dist/chunks/{ScopedLogger-D-7q8uVP.js.map → ScopedLogger-D2HzayKH.js.map} +1 -1
  14. package/dist/chunks/environment--eaTrhRu.js +4 -0
  15. package/dist/chunks/environment--eaTrhRu.js.map +1 -0
  16. package/dist/chunks/environment-BanAyF-K.js +1172 -0
  17. package/dist/chunks/environment-BanAyF-K.js.map +1 -0
  18. package/dist/chunks/formatting-BSNvAxLK.js +2 -0
  19. package/dist/chunks/formatting-BSNvAxLK.js.map +1 -0
  20. package/dist/chunks/formatting-CgQSWgXR.js +380 -0
  21. package/dist/chunks/formatting-CgQSWgXR.js.map +1 -0
  22. package/dist/cli/CommandProcessor.d.ts.map +1 -0
  23. package/dist/cli/commands/ConfigCommand.d.ts.map +1 -0
  24. package/dist/cli/commands/ExportCommand.d.ts.map +1 -0
  25. package/dist/cli/commands/HistoryCommand.d.ts.map +1 -0
  26. package/dist/cli/commands/StatusCommand.d.ts.map +1 -0
  27. package/dist/cli/commands/ThemeCommand.d.ts.map +1 -0
  28. package/dist/cli/help.d.ts.map +1 -0
  29. package/dist/cli/index.d.ts.map +1 -0
  30. package/dist/{types/constants.d.ts → constants.d.ts} +108 -0
  31. package/dist/constants.d.ts.map +1 -0
  32. package/dist/core.cjs +1 -1
  33. package/dist/core.cjs.map +1 -1
  34. package/dist/core.d.ts +127 -0
  35. package/dist/core.d.ts.map +1 -0
  36. package/dist/core.js +6 -5
  37. package/dist/core.js.map +1 -1
  38. package/dist/example.d.ts.map +1 -0
  39. package/dist/exports-module.d.ts.map +1 -0
  40. package/dist/exports.cjs +1 -1
  41. package/dist/exports.js +2 -2
  42. package/dist/handlers/AnalyticsLogHandler.d.ts.map +1 -0
  43. package/dist/handlers/ExportLogHandler.d.ts.map +1 -0
  44. package/dist/handlers/FileLogHandler.d.ts.map +1 -0
  45. package/dist/handlers/RemoteLogHandler.d.ts.map +1 -0
  46. package/dist/handlers/index.d.ts.map +1 -0
  47. package/dist/index.cjs +1 -1
  48. package/dist/index.cjs.map +1 -1
  49. package/dist/index.d.ts +124 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +25 -5
  52. package/dist/index.js.map +1 -1
  53. package/dist/main.d.ts.map +1 -0
  54. package/dist/styling/LogStyleBuilder.d.ts.map +1 -0
  55. package/dist/styling/SemanticStyles.d.ts.map +1 -0
  56. package/dist/styling/SmartPresets.d.ts.map +1 -0
  57. package/dist/styling/StyleBuilder.d.ts.map +1 -0
  58. package/dist/styling/banners.d.ts.map +1 -0
  59. package/dist/styling/index.d.ts.map +1 -0
  60. package/dist/styling/themes.d.ts.map +1 -0
  61. package/dist/styling-module.d.ts.map +1 -0
  62. package/dist/styling.cjs +1 -1
  63. package/dist/styling.js +3 -3
  64. package/dist/terminal/terminal-renderer.d.ts +63 -0
  65. package/dist/terminal/terminal-renderer.d.ts.map +1 -0
  66. package/dist/types/core.d.ts +229 -122
  67. package/dist/types/core.d.ts.map +1 -1
  68. package/dist/types/handlers.d.ts.map +1 -0
  69. package/dist/types/index.d.ts +4 -119
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/dist/utils/adapter.d.ts +48 -0
  72. package/dist/utils/adapter.d.ts.map +1 -0
  73. package/dist/utils/ansi-colors.d.ts +156 -0
  74. package/dist/utils/ansi-colors.d.ts.map +1 -0
  75. package/dist/utils/environment-detector.d.ts +35 -0
  76. package/dist/utils/environment-detector.d.ts.map +1 -0
  77. package/dist/{types/utils → utils}/environment.d.ts +1 -1
  78. package/dist/utils/environment.d.ts.map +1 -0
  79. package/dist/{types/utils → utils}/formatting.d.ts +22 -1
  80. package/dist/utils/formatting.d.ts.map +1 -0
  81. package/dist/{types/utils → utils}/index.d.ts +1 -0
  82. package/dist/utils/index.d.ts.map +1 -0
  83. package/dist/utils/opentui-detection.d.ts.map +1 -0
  84. package/dist/{types/utils → utils}/output.d.ts +7 -2
  85. package/dist/utils/output.d.ts.map +1 -0
  86. package/dist/utils/stackTrace.d.ts.map +1 -0
  87. package/dist/utils/timestamps.d.ts.map +1 -0
  88. package/package.json +10 -2
  89. package/src/Logger.ts +24 -19
  90. package/src/constants.ts +131 -1
  91. package/src/core.ts +11 -7
  92. package/src/handlers/ExportLogHandler.ts +2 -1
  93. package/src/index.ts +30 -2
  94. package/src/styling/SemanticStyles.ts +1 -1
  95. package/src/terminal/terminal-renderer.ts +339 -0
  96. package/src/types/core.ts +15 -1
  97. package/src/types/index.ts +1 -0
  98. package/src/utils/adapter.ts +291 -0
  99. package/src/utils/ansi-colors.ts +333 -0
  100. package/src/utils/environment-detector.ts +148 -0
  101. package/src/utils/formatting.ts +196 -6
  102. package/src/utils/index.ts +23 -11
  103. package/src/utils/output.ts +43 -1
  104. package/vite.config.ts +1 -1
  105. package/dist/chunks/Logger-CTAaDeZi.js.map +0 -1
  106. package/dist/chunks/Logger-D8pK7XXt.js.map +0 -1
  107. package/dist/chunks/environment-Bxbnw4pd.js +0 -544
  108. package/dist/chunks/environment-Bxbnw4pd.js.map +0 -1
  109. package/dist/chunks/environment-Dm66zOML.js +0 -4
  110. package/dist/chunks/environment-Dm66zOML.js.map +0 -1
  111. package/dist/chunks/formatting-C0riPC5_.js +0 -95
  112. package/dist/chunks/formatting-C0riPC5_.js.map +0 -1
  113. package/dist/chunks/formatting-DNCAV66-.js +0 -2
  114. package/dist/chunks/formatting-DNCAV66-.js.map +0 -1
  115. package/dist/types/Logger.d.ts.map +0 -1
  116. package/dist/types/ScopedLogger.d.ts.map +0 -1
  117. package/dist/types/cli/CommandProcessor.d.ts.map +0 -1
  118. package/dist/types/cli/commands/ConfigCommand.d.ts.map +0 -1
  119. package/dist/types/cli/commands/ExportCommand.d.ts.map +0 -1
  120. package/dist/types/cli/commands/HistoryCommand.d.ts.map +0 -1
  121. package/dist/types/cli/commands/StatusCommand.d.ts.map +0 -1
  122. package/dist/types/cli/commands/ThemeCommand.d.ts.map +0 -1
  123. package/dist/types/cli/help.d.ts.map +0 -1
  124. package/dist/types/cli/index.d.ts.map +0 -1
  125. package/dist/types/constants.d.ts.map +0 -1
  126. package/dist/types/example.d.ts.map +0 -1
  127. package/dist/types/exports-module.d.ts.map +0 -1
  128. package/dist/types/handlers/AnalyticsLogHandler.d.ts.map +0 -1
  129. package/dist/types/handlers/ExportLogHandler.d.ts.map +0 -1
  130. package/dist/types/handlers/FileLogHandler.d.ts.map +0 -1
  131. package/dist/types/handlers/RemoteLogHandler.d.ts.map +0 -1
  132. package/dist/types/handlers/index.d.ts.map +0 -1
  133. package/dist/types/main.d.ts.map +0 -1
  134. package/dist/types/styling/LogStyleBuilder.d.ts.map +0 -1
  135. package/dist/types/styling/SemanticStyles.d.ts.map +0 -1
  136. package/dist/types/styling/SmartPresets.d.ts.map +0 -1
  137. package/dist/types/styling/StyleBuilder.d.ts.map +0 -1
  138. package/dist/types/styling/banners.d.ts.map +0 -1
  139. package/dist/types/styling/index.d.ts.map +0 -1
  140. package/dist/types/styling/themes.d.ts.map +0 -1
  141. package/dist/types/styling-module.d.ts.map +0 -1
  142. package/dist/types/types/core.d.ts +0 -221
  143. package/dist/types/types/core.d.ts.map +0 -1
  144. package/dist/types/types/handlers.d.ts.map +0 -1
  145. package/dist/types/types/index.d.ts +0 -7
  146. package/dist/types/types/index.d.ts.map +0 -1
  147. package/dist/types/utils/environment.d.ts.map +0 -1
  148. package/dist/types/utils/formatting.d.ts.map +0 -1
  149. package/dist/types/utils/index.d.ts.map +0 -1
  150. package/dist/types/utils/opentui-detection.d.ts.map +0 -1
  151. package/dist/types/utils/output.d.ts.map +0 -1
  152. package/dist/types/utils/stackTrace.d.ts.map +0 -1
  153. package/dist/types/utils/timestamps.d.ts.map +0 -1
  154. /package/dist/{types/Logger.d.ts → Logger.d.ts} +0 -0
  155. /package/dist/{types/ScopedLogger.d.ts → ScopedLogger.d.ts} +0 -0
  156. /package/dist/{types/cli → cli}/CommandProcessor.d.ts +0 -0
  157. /package/dist/{types/cli → cli}/commands/ConfigCommand.d.ts +0 -0
  158. /package/dist/{types/cli → cli}/commands/ExportCommand.d.ts +0 -0
  159. /package/dist/{types/cli → cli}/commands/HistoryCommand.d.ts +0 -0
  160. /package/dist/{types/cli → cli}/commands/StatusCommand.d.ts +0 -0
  161. /package/dist/{types/cli → cli}/commands/ThemeCommand.d.ts +0 -0
  162. /package/dist/{types/cli → cli}/help.d.ts +0 -0
  163. /package/dist/{types/cli → cli}/index.d.ts +0 -0
  164. /package/dist/{types/example.d.ts → example.d.ts} +0 -0
  165. /package/dist/{types/exports-module.d.ts → exports-module.d.ts} +0 -0
  166. /package/dist/{types/handlers → handlers}/AnalyticsLogHandler.d.ts +0 -0
  167. /package/dist/{types/handlers → handlers}/ExportLogHandler.d.ts +0 -0
  168. /package/dist/{types/handlers → handlers}/FileLogHandler.d.ts +0 -0
  169. /package/dist/{types/handlers → handlers}/RemoteLogHandler.d.ts +0 -0
  170. /package/dist/{types/handlers → handlers}/index.d.ts +0 -0
  171. /package/dist/{types/main.d.ts → main.d.ts} +0 -0
  172. /package/dist/{types/styling → styling}/LogStyleBuilder.d.ts +0 -0
  173. /package/dist/{types/styling → styling}/SemanticStyles.d.ts +0 -0
  174. /package/dist/{types/styling → styling}/SmartPresets.d.ts +0 -0
  175. /package/dist/{types/styling → styling}/StyleBuilder.d.ts +0 -0
  176. /package/dist/{types/styling → styling}/banners.d.ts +0 -0
  177. /package/dist/{types/styling → styling}/index.d.ts +0 -0
  178. /package/dist/{types/styling → styling}/themes.d.ts +0 -0
  179. /package/dist/{types/styling-module.d.ts → styling-module.d.ts} +0 -0
  180. /package/dist/types/{types/handlers.d.ts → handlers.d.ts} +0 -0
  181. /package/dist/{types/utils → utils}/opentui-detection.d.ts +0 -0
  182. /package/dist/{types/utils → utils}/stackTrace.d.ts +0 -0
  183. /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
+ }
@@ -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