@adaas/a-utils 0.1.28 → 0.1.30
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/LICENSE +1 -1
- package/dist/index.cjs +18 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +402 -21
- package/dist/index.d.ts +402 -21
- package/dist/index.mjs +18 -28
- package/dist/index.mjs.map +1 -1
- package/examples/A-Logger-examples.ts +101 -24
- package/package.json +5 -5
- package/src/index.ts +16 -0
- package/src/lib/A-Logger/A-Logger.component.ts +385 -70
- package/src/lib/A-Logger/A-Logger.constants.ts +13 -0
- package/src/lib/A-Logger/A-Logger.types.ts +12 -1
- package/src/lib/A-Logger/README.md +116 -12
- package/src/lib/A-Memory/A-Memory.component.ts +0 -3
- package/src/lib/A-Route/A-Route.entity.ts +136 -0
- package/src/lib/A-Route/A-Route.types.ts +1 -0
- package/src/lib/A-Signal/A-Signal.constants.ts +10 -0
- package/src/lib/A-Signal/A-Signal.error.ts +0 -0
- package/src/lib/A-Signal/A-Signal.types.ts +47 -0
- package/src/lib/A-Signal/components/A-SignalBus.component.ts +103 -0
- package/src/lib/A-Signal/context/A-SignalConfig.context.ts +81 -0
- package/src/lib/A-Signal/context/A-SignalState.context.ts +197 -0
- package/src/lib/A-Signal/entities/A-Signal.entity.ts +42 -0
- package/src/lib/A-Signal/entities/A-SignalVector.entity.ts +83 -0
- package/src/lib/A-StateMachine/A-StateMachine.component.ts +2 -1
- package/tests/A-Logger.test.ts +90 -5
- package/tests/A-Route.test.ts +34 -0
- package/tests/A-Signal.test.ts +66 -0
- package/examples/config.ts +0 -33
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { A_Component, A_Context, A_Error, A_Inject, A_Scope } from "@adaas/a-concept";
|
|
2
2
|
import { A_Config } from "../A-Config/A-Config.context";
|
|
3
3
|
import { A_LoggerEnvVariablesType } from "./A-Logger.env";
|
|
4
|
-
import { A_LoggerLevel } from "./A-Logger.types";
|
|
4
|
+
import { A_LoggerLevel, A_LoggerColorName } from "./A-Logger.types";
|
|
5
5
|
import {
|
|
6
6
|
A_LOGGER_DEFAULT_SCOPE_LENGTH,
|
|
7
7
|
A_LOGGER_COLORS,
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
A_LOGGER_TIME_FORMAT,
|
|
10
10
|
A_LOGGER_FORMAT,
|
|
11
11
|
A_LOGGER_ENV_KEYS,
|
|
12
|
-
A_LOGGER_SAFE_RANDOM_COLORS
|
|
12
|
+
A_LOGGER_SAFE_RANDOM_COLORS,
|
|
13
|
+
A_LOGGER_TERMINAL
|
|
13
14
|
} from "./A-Logger.constants";
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -40,7 +41,15 @@ import {
|
|
|
40
41
|
* doSomething() {
|
|
41
42
|
* this.logger.info('Processing started'); // Uses scope-name-based colors, always shows
|
|
42
43
|
* this.logger.debug('Debug information'); // Only shows when debug level enabled
|
|
43
|
-
*
|
|
44
|
+
*
|
|
45
|
+
* // Color overload methods with enum support
|
|
46
|
+
* this.logger.info('green', 'Success message'); // Green message, scope stays default
|
|
47
|
+
* this.logger.debug('gray', 'Verbose debug info'); // Gray message for less important info
|
|
48
|
+
* this.logger.info('brightBlue', 'Important notification');
|
|
49
|
+
*
|
|
50
|
+
* // Terminal width aware formatting - automatically wraps long lines
|
|
51
|
+
* this.logger.info('This is a very long message that will be automatically wrapped to fit within the terminal width while maintaining proper indentation and formatting');
|
|
52
|
+
*
|
|
44
53
|
* this.logger.warning('Something might be wrong');
|
|
45
54
|
* this.logger.error(new Error('Something failed'));
|
|
46
55
|
* }
|
|
@@ -50,6 +59,13 @@ import {
|
|
|
50
59
|
* const logger1 = new A_Logger(new A_Scope({name: 'UserService'})); // Gets consistent colors
|
|
51
60
|
* const logger2 = new A_Logger(new A_Scope({name: 'UserService'})); // Gets same colors as logger1
|
|
52
61
|
*
|
|
62
|
+
* // Available color names (A_LoggerColorName enum):
|
|
63
|
+
* // 'red', 'yellow', 'green', 'blue', 'cyan', 'magenta', 'gray',
|
|
64
|
+
* // 'brightBlue', 'brightCyan', 'brightMagenta', 'darkGray', 'lightGray',
|
|
65
|
+
* // 'indigo', 'violet', 'purple', 'lavender', 'skyBlue', 'steelBlue',
|
|
66
|
+
* // 'slateBlue', 'deepBlue', 'lightBlue', 'periwinkle', 'cornflower',
|
|
67
|
+
* // 'powder', 'charcoal', 'silver', 'smoke', 'slate'
|
|
68
|
+
*
|
|
53
69
|
* // Configuration via environment variables or A_Config (overrides automatic selection)
|
|
54
70
|
* process.env.A_LOGGER_DEFAULT_SCOPE_COLOR = 'magenta';
|
|
55
71
|
* process.env.A_LOGGER_DEFAULT_LOG_COLOR = 'green';
|
|
@@ -93,9 +109,21 @@ export class A_Logger extends A_Component {
|
|
|
93
109
|
*/
|
|
94
110
|
private readonly DEFAULT_LOG_COLOR: keyof typeof A_LOGGER_COLORS;
|
|
95
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Current terminal width for responsive formatting
|
|
114
|
+
* Automatically detected or falls back to default values
|
|
115
|
+
*/
|
|
116
|
+
private readonly TERMINAL_WIDTH: number;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Maximum content width based on terminal size
|
|
120
|
+
* Used for word wrapping and line length calculations
|
|
121
|
+
*/
|
|
122
|
+
private readonly MAX_CONTENT_WIDTH: number;
|
|
123
|
+
|
|
96
124
|
// =============================================
|
|
97
125
|
// Constructor and Initialization
|
|
98
|
-
//
|
|
126
|
+
// =============================
|
|
99
127
|
|
|
100
128
|
/**
|
|
101
129
|
* Initialize A_Logger with dependency injection
|
|
@@ -126,6 +154,10 @@ export class A_Logger extends A_Component {
|
|
|
126
154
|
this.DEFAULT_SCOPE_COLOR = complementaryColors.scopeColor;
|
|
127
155
|
this.DEFAULT_LOG_COLOR = complementaryColors.logColor;
|
|
128
156
|
}
|
|
157
|
+
|
|
158
|
+
// Initialize terminal width detection
|
|
159
|
+
this.TERMINAL_WIDTH = this.detectTerminalWidth();
|
|
160
|
+
this.MAX_CONTENT_WIDTH = Math.floor(this.TERMINAL_WIDTH * A_LOGGER_TERMINAL.MAX_LINE_LENGTH_RATIO);
|
|
129
161
|
}
|
|
130
162
|
|
|
131
163
|
// =============================================
|
|
@@ -191,8 +223,129 @@ export class A_Logger extends A_Component {
|
|
|
191
223
|
}
|
|
192
224
|
|
|
193
225
|
// =============================================
|
|
194
|
-
//
|
|
226
|
+
// Terminal Width Detection
|
|
227
|
+
// =============================================
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Detect current terminal width based on environment
|
|
231
|
+
*
|
|
232
|
+
* Returns appropriate width for different environments:
|
|
233
|
+
* - Node.js: Uses process.stdout.columns if available
|
|
234
|
+
* - Browser: Returns browser default width
|
|
235
|
+
* - Fallback: Returns default terminal width
|
|
236
|
+
*
|
|
237
|
+
* @returns Terminal width in characters
|
|
238
|
+
*/
|
|
239
|
+
private detectTerminalWidth(): number {
|
|
240
|
+
try {
|
|
241
|
+
// Browser environment
|
|
242
|
+
if (A_Context.environment === 'browser') {
|
|
243
|
+
return A_LOGGER_TERMINAL.BROWSER_DEFAULT_WIDTH;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Node.js environment - try to get actual terminal width
|
|
247
|
+
if (typeof process !== 'undefined' && process.stdout && process.stdout.columns) {
|
|
248
|
+
const cols = process.stdout.columns;
|
|
249
|
+
// Ensure minimum width for readability
|
|
250
|
+
return Math.max(cols, A_LOGGER_TERMINAL.MIN_WIDTH);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Fallback to default width
|
|
254
|
+
return A_LOGGER_TERMINAL.DEFAULT_WIDTH;
|
|
255
|
+
} catch (error) {
|
|
256
|
+
// If any error occurs, fall back to default width
|
|
257
|
+
return A_LOGGER_TERMINAL.DEFAULT_WIDTH;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Wrap text to fit within terminal width while preserving formatting
|
|
263
|
+
*
|
|
264
|
+
* @param text - Text to wrap
|
|
265
|
+
* @param scopePadding - The scope padding string for alignment
|
|
266
|
+
* @param isFirstLine - Whether this is the first line (affects available width calculation)
|
|
267
|
+
* @returns Array of wrapped lines with proper indentation
|
|
268
|
+
*/
|
|
269
|
+
private wrapText(text: string, scopePadding: string, isFirstLine: boolean = true): string[] {
|
|
270
|
+
if (A_Context.environment === 'browser') {
|
|
271
|
+
// In browser, don't wrap - let browser console handle it
|
|
272
|
+
return [text];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Calculate available width for text content
|
|
276
|
+
// First line: terminal_width - scope_header_length (includes [scope] |time| part)
|
|
277
|
+
// Continuation lines: terminal_width - scope_padding - pipe_length
|
|
278
|
+
const scopeHeaderLength = this.formattedScope.length + 4 + this.getTime().length + 4; // [scope] |time|
|
|
279
|
+
const continuationIndent = `${scopePadding}${A_LOGGER_FORMAT.PIPE}`;
|
|
280
|
+
|
|
281
|
+
const firstLineMaxWidth = Math.max(this.TERMINAL_WIDTH - scopeHeaderLength - 1, 20); // -1 for space
|
|
282
|
+
const continuationMaxWidth = Math.max(this.TERMINAL_WIDTH - continuationIndent.length, 20);
|
|
283
|
+
|
|
284
|
+
// If text fits on first line, return as is
|
|
285
|
+
if (isFirstLine && text.length <= firstLineMaxWidth) {
|
|
286
|
+
return [text];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const lines: string[] = [];
|
|
290
|
+
const words = text.split(' ');
|
|
291
|
+
let currentLine = '';
|
|
292
|
+
let currentMaxWidth = isFirstLine ? firstLineMaxWidth : continuationMaxWidth;
|
|
293
|
+
let isCurrentLineFirst = isFirstLine;
|
|
294
|
+
|
|
295
|
+
for (const word of words) {
|
|
296
|
+
const spaceNeeded = currentLine ? 1 : 0; // Space before word
|
|
297
|
+
const totalLength = currentLine.length + spaceNeeded + word.length;
|
|
298
|
+
|
|
299
|
+
// If adding this word would exceed current line's max width
|
|
300
|
+
if (totalLength > currentMaxWidth) {
|
|
301
|
+
if (currentLine) {
|
|
302
|
+
lines.push(currentLine);
|
|
303
|
+
currentLine = word;
|
|
304
|
+
// After first line, all subsequent lines use continuation width
|
|
305
|
+
currentMaxWidth = continuationMaxWidth;
|
|
306
|
+
isCurrentLineFirst = false;
|
|
307
|
+
} else {
|
|
308
|
+
// Word itself is too long, split it
|
|
309
|
+
if (word.length > currentMaxWidth) {
|
|
310
|
+
const chunks = this.splitLongWord(word, currentMaxWidth);
|
|
311
|
+
lines.push(...chunks.slice(0, -1));
|
|
312
|
+
currentLine = chunks[chunks.length - 1];
|
|
313
|
+
} else {
|
|
314
|
+
currentLine = word;
|
|
315
|
+
}
|
|
316
|
+
currentMaxWidth = continuationMaxWidth;
|
|
317
|
+
isCurrentLineFirst = false;
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
currentLine += (currentLine ? ' ' : '') + word;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (currentLine) {
|
|
325
|
+
lines.push(currentLine);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return lines.length ? lines : [text];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Split a long word that doesn't fit on a single line
|
|
333
|
+
*
|
|
334
|
+
* @param word - Word to split
|
|
335
|
+
* @param maxLength - Maximum length per chunk
|
|
336
|
+
* @returns Array of word chunks
|
|
337
|
+
*/
|
|
338
|
+
private splitLongWord(word: string, maxLength: number): string[] {
|
|
339
|
+
const chunks: string[] = [];
|
|
340
|
+
for (let i = 0; i < word.length; i += maxLength) {
|
|
341
|
+
chunks.push(word.slice(i, i + maxLength));
|
|
342
|
+
}
|
|
343
|
+
return chunks;
|
|
344
|
+
}
|
|
345
|
+
|
|
195
346
|
// =============================================
|
|
347
|
+
// Factory Methods
|
|
348
|
+
// =============================
|
|
196
349
|
|
|
197
350
|
|
|
198
351
|
|
|
@@ -249,14 +402,16 @@ export class A_Logger extends A_Component {
|
|
|
249
402
|
*
|
|
250
403
|
* @param messageColor - The color key to apply to the message content
|
|
251
404
|
* @param args - Variable arguments to format and display
|
|
252
|
-
* @returns Array of formatted strings ready for console output
|
|
405
|
+
* @returns Array of formatted strings and/or objects ready for console output
|
|
253
406
|
*/
|
|
254
407
|
compile(
|
|
255
408
|
messageColor: keyof typeof this.COLORS,
|
|
256
409
|
...args: any[]
|
|
257
|
-
): Array<
|
|
410
|
+
): Array<any> {
|
|
258
411
|
const timeString = this.getTime();
|
|
259
|
-
|
|
412
|
+
// Calculate padding based on actual displayed scope width (STANDARD_SCOPE_LENGTH)
|
|
413
|
+
// Plus 3 for the brackets and space: [scope]
|
|
414
|
+
const scopePadding = ' '.repeat(this.STANDARD_SCOPE_LENGTH + 3);
|
|
260
415
|
const isMultiArg = args.length > 1;
|
|
261
416
|
|
|
262
417
|
return [
|
|
@@ -293,41 +448,100 @@ export class A_Logger extends A_Component {
|
|
|
293
448
|
}
|
|
294
449
|
|
|
295
450
|
/**
|
|
296
|
-
* Format an object for display with proper JSON indentation
|
|
451
|
+
* Format an object for display with proper JSON indentation and terminal width awareness
|
|
297
452
|
*
|
|
298
453
|
* @param obj - The object to format
|
|
299
454
|
* @param shouldAddNewline - Whether to add a newline prefix
|
|
300
455
|
* @param scopePadding - The padding string for consistent alignment
|
|
301
|
-
* @returns Formatted object string
|
|
456
|
+
* @returns Formatted object string or the object itself for browser environments
|
|
302
457
|
*/
|
|
303
|
-
private formatObject(obj: any, shouldAddNewline: boolean, scopePadding: string):
|
|
458
|
+
private formatObject(obj: any, shouldAddNewline: boolean, scopePadding: string): any {
|
|
304
459
|
|
|
305
|
-
//
|
|
306
|
-
|
|
460
|
+
// In case it's browser, return the object as is to use native console object rendering
|
|
461
|
+
// This allows the browser console to display objects with its native interactive features
|
|
462
|
+
if (A_Context.environment === 'browser') {
|
|
307
463
|
return obj;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Handle null and undefined values
|
|
467
|
+
if (obj === null) {
|
|
468
|
+
return shouldAddNewline ? `\n${scopePadding}${A_LOGGER_FORMAT.PIPE}null` : 'null';
|
|
469
|
+
}
|
|
470
|
+
if (obj === undefined) {
|
|
471
|
+
return shouldAddNewline ? `\n${scopePadding}${A_LOGGER_FORMAT.PIPE}undefined` : 'undefined';
|
|
472
|
+
}
|
|
308
473
|
|
|
309
474
|
let jsonString: string;
|
|
310
475
|
try {
|
|
311
476
|
jsonString = JSON.stringify(obj, null, 2);
|
|
312
477
|
} catch (error) {
|
|
313
|
-
// Handle circular references
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (
|
|
318
|
-
|
|
478
|
+
// Handle circular references and other JSON errors
|
|
479
|
+
try {
|
|
480
|
+
const seen = new WeakSet();
|
|
481
|
+
jsonString = JSON.stringify(obj, (key, value) => {
|
|
482
|
+
if (typeof value === 'object' && value !== null) {
|
|
483
|
+
if (seen.has(value)) {
|
|
484
|
+
return '[Circular Reference]';
|
|
485
|
+
}
|
|
486
|
+
seen.add(value);
|
|
319
487
|
}
|
|
320
|
-
|
|
488
|
+
return value;
|
|
489
|
+
}, 2);
|
|
490
|
+
} catch (fallbackError) {
|
|
491
|
+
// If all else fails, convert to string
|
|
492
|
+
jsonString = String(obj);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Apply terminal width wrapping to long JSON string values
|
|
497
|
+
const continuationIndent = `${scopePadding}${A_LOGGER_FORMAT.PIPE}`;
|
|
498
|
+
const maxJsonLineWidth = this.TERMINAL_WIDTH - continuationIndent.length - 4; // -4 for JSON indentation
|
|
499
|
+
|
|
500
|
+
// Split into lines and wrap long string values
|
|
501
|
+
const lines = jsonString.split('\n').map(line => {
|
|
502
|
+
// Check if this line contains a long string value
|
|
503
|
+
const stringValueMatch = line.match(/^(\s*"[^"]+":\s*")([^"]+)(".*)?$/);
|
|
504
|
+
if (stringValueMatch && stringValueMatch[2].length > maxJsonLineWidth - stringValueMatch[1].length - (stringValueMatch[3] || '').length) {
|
|
505
|
+
const [, prefix, value, suffix = ''] = stringValueMatch;
|
|
506
|
+
|
|
507
|
+
// Wrap the string value if it's too long
|
|
508
|
+
if (value.length > maxJsonLineWidth - prefix.length - suffix.length) {
|
|
509
|
+
const wrappedValue = this.wrapJsonStringValue(value, maxJsonLineWidth - prefix.length - suffix.length);
|
|
510
|
+
return prefix + wrappedValue + suffix;
|
|
321
511
|
}
|
|
322
|
-
|
|
323
|
-
|
|
512
|
+
}
|
|
513
|
+
return line;
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
const formatted = lines.join('\n' + continuationIndent);
|
|
517
|
+
return shouldAddNewline ? '\n' + continuationIndent + formatted : formatted;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Wrap a long JSON string value while preserving readability
|
|
522
|
+
*
|
|
523
|
+
* @param value - The string value to wrap
|
|
524
|
+
* @param maxWidth - Maximum width for the value
|
|
525
|
+
* @returns Wrapped string value
|
|
526
|
+
*/
|
|
527
|
+
private wrapJsonStringValue(value: string, maxWidth: number): string {
|
|
528
|
+
if (value.length <= maxWidth) {
|
|
529
|
+
return value;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// For JSON string values, truncate with ellipsis to maintain JSON validity
|
|
533
|
+
// This prevents the JSON from becoming unreadable due to excessive wrapping
|
|
534
|
+
// while still showing the most important part of the string
|
|
535
|
+
if (maxWidth > 6) { // Ensure we have room for ellipsis
|
|
536
|
+
return value.substring(0, maxWidth - 3) + '...';
|
|
537
|
+
} else {
|
|
538
|
+
// If maxWidth is very small, just return truncated value
|
|
539
|
+
return value.substring(0, Math.max(1, maxWidth));
|
|
324
540
|
}
|
|
325
|
-
const formatted = jsonString.replace(/\n/g, '\n' + `${scopePadding}${A_LOGGER_FORMAT.PIPE}`);
|
|
326
|
-
return shouldAddNewline ? '\n' + `${scopePadding}${A_LOGGER_FORMAT.PIPE}` + formatted : formatted;
|
|
327
541
|
}
|
|
328
542
|
|
|
329
543
|
/**
|
|
330
|
-
* Format a string for display with proper indentation
|
|
544
|
+
* Format a string for display with proper indentation and terminal width wrapping
|
|
331
545
|
*
|
|
332
546
|
* @param str - The string to format
|
|
333
547
|
* @param shouldAddNewline - Whether to add a newline prefix
|
|
@@ -335,8 +549,32 @@ export class A_Logger extends A_Component {
|
|
|
335
549
|
* @returns Formatted string
|
|
336
550
|
*/
|
|
337
551
|
private formatString(str: string, shouldAddNewline: boolean, scopePadding: string): string {
|
|
338
|
-
|
|
339
|
-
|
|
552
|
+
// In browser environment, keep simple formatting
|
|
553
|
+
if (A_Context.environment === 'browser') {
|
|
554
|
+
const prefix = shouldAddNewline ? '\n' : '';
|
|
555
|
+
return (prefix + str).replace(/\n/g, '\n' + `${scopePadding}${A_LOGGER_FORMAT.PIPE}`);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// For terminal, apply intelligent text wrapping
|
|
559
|
+
const wrappedLines = this.wrapText(str, scopePadding, !shouldAddNewline);
|
|
560
|
+
const continuationIndent = `${scopePadding}${A_LOGGER_FORMAT.PIPE}`;
|
|
561
|
+
|
|
562
|
+
// Format the wrapped lines with proper indentation
|
|
563
|
+
const formattedLines = wrappedLines.map((line, index) => {
|
|
564
|
+
if (index === 0 && !shouldAddNewline) {
|
|
565
|
+
// First line in inline mode (no newline prefix)
|
|
566
|
+
return line;
|
|
567
|
+
} else {
|
|
568
|
+
// Continuation lines or first line with newline prefix
|
|
569
|
+
return `${continuationIndent}${line}`;
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
if (shouldAddNewline) {
|
|
574
|
+
return '\n' + formattedLines.join('\n');
|
|
575
|
+
} else {
|
|
576
|
+
return formattedLines.join('\n');
|
|
577
|
+
}
|
|
340
578
|
}
|
|
341
579
|
|
|
342
580
|
// =============================================
|
|
@@ -391,7 +629,7 @@ export class A_Logger extends A_Component {
|
|
|
391
629
|
* Note: The scope color always remains the instance's default scope color,
|
|
392
630
|
* only the message content color changes when explicitly specified.
|
|
393
631
|
*
|
|
394
|
-
* @param color - Optional color
|
|
632
|
+
* @param color - Optional color name from A_LoggerColorName enum or the first message argument
|
|
395
633
|
* @param args - Additional arguments to log
|
|
396
634
|
*
|
|
397
635
|
* @example
|
|
@@ -401,7 +639,7 @@ export class A_Logger extends A_Component {
|
|
|
401
639
|
* logger.debug('Processing user:', { id: 1, name: 'John' });
|
|
402
640
|
* ```
|
|
403
641
|
*/
|
|
404
|
-
debug(color:
|
|
642
|
+
debug(color: A_LoggerColorName, ...args: any[]): void;
|
|
405
643
|
debug(...args: any[]): void;
|
|
406
644
|
debug(param1: any, ...args: any[]): void {
|
|
407
645
|
if (!this.shouldLog('debug')) return;
|
|
@@ -426,7 +664,7 @@ export class A_Logger extends A_Component {
|
|
|
426
664
|
* Note: The scope color always remains the instance's default scope color,
|
|
427
665
|
* only the message content color changes when explicitly specified.
|
|
428
666
|
*
|
|
429
|
-
* @param color - Optional color
|
|
667
|
+
* @param color - Optional color name from A_LoggerColorName enum or the first message argument
|
|
430
668
|
* @param args - Additional arguments to log
|
|
431
669
|
*
|
|
432
670
|
* @example
|
|
@@ -436,7 +674,7 @@ export class A_Logger extends A_Component {
|
|
|
436
674
|
* logger.info('Processing user:', { id: 1, name: 'John' });
|
|
437
675
|
* ```
|
|
438
676
|
*/
|
|
439
|
-
info(color:
|
|
677
|
+
info(color: A_LoggerColorName, ...args: any[]): void;
|
|
440
678
|
info(...args: any[]): void;
|
|
441
679
|
info(param1: any, ...args: any[]): void {
|
|
442
680
|
if (!this.shouldLog('info')) return;
|
|
@@ -454,10 +692,10 @@ export class A_Logger extends A_Component {
|
|
|
454
692
|
* Legacy log method (kept for backward compatibility)
|
|
455
693
|
* @deprecated Use info() method instead
|
|
456
694
|
*
|
|
457
|
-
* @param color - Optional color
|
|
695
|
+
* @param color - Optional color name from A_LoggerColorName enum or the first message argument
|
|
458
696
|
* @param args - Additional arguments to log
|
|
459
697
|
*/
|
|
460
|
-
log(color:
|
|
698
|
+
log(color: A_LoggerColorName, ...args: any[]): void;
|
|
461
699
|
log(...args: any[]): void;
|
|
462
700
|
log(param1: any, ...args: any[]): void {
|
|
463
701
|
// Delegate to info method for backward compatibility
|
|
@@ -515,7 +753,7 @@ export class A_Logger extends A_Component {
|
|
|
515
753
|
*/
|
|
516
754
|
protected log_A_Error(error: A_Error): void {
|
|
517
755
|
const time = this.getTime();
|
|
518
|
-
const scopePadding = ' '.repeat(this.
|
|
756
|
+
const scopePadding = ' '.repeat(this.STANDARD_SCOPE_LENGTH + 3);
|
|
519
757
|
|
|
520
758
|
console.log(`\x1b[31m[${this.formattedScope}] |${time}| ERROR ${error.code}
|
|
521
759
|
${scopePadding}| ${error.message}
|
|
@@ -537,59 +775,136 @@ ${scopePadding}|-------------------------------
|
|
|
537
775
|
/**
|
|
538
776
|
* Format A_Error instances for inline display within compiled messages
|
|
539
777
|
*
|
|
540
|
-
* Provides detailed formatting for A_Error objects
|
|
541
|
-
* - Error code and
|
|
542
|
-
* -
|
|
543
|
-
* -
|
|
778
|
+
* Provides detailed formatting for A_Error objects with:
|
|
779
|
+
* - Error code, message, and description
|
|
780
|
+
* - Original error information FIRST (better UX for debugging)
|
|
781
|
+
* - Stack traces with terminal width awareness
|
|
544
782
|
* - Documentation links (if available)
|
|
783
|
+
* - Consistent formatting with rest of logger
|
|
545
784
|
*
|
|
546
785
|
* @param error - The A_Error instance to format
|
|
547
786
|
* @returns Formatted string ready for display
|
|
548
787
|
*/
|
|
549
788
|
protected compile_A_Error(error: A_Error): string {
|
|
550
|
-
const
|
|
789
|
+
const continuationIndent = `${' '.repeat(this.STANDARD_SCOPE_LENGTH + 3)}${A_LOGGER_FORMAT.PIPE}`;
|
|
790
|
+
const separator = `${continuationIndent}-------------------------------`;
|
|
791
|
+
const lines: string[] = [];
|
|
792
|
+
|
|
793
|
+
// Add error header
|
|
794
|
+
lines.push('');
|
|
795
|
+
lines.push(separator);
|
|
796
|
+
lines.push(`${continuationIndent}A_ERROR: ${error.code}`);
|
|
797
|
+
lines.push(separator);
|
|
798
|
+
|
|
799
|
+
// Format and wrap error message and description
|
|
800
|
+
const errorMessage = this.wrapText(`Message: ${error.message}`, continuationIndent, false);
|
|
801
|
+
const errorDescription = this.wrapText(`Description: ${error.description}`, continuationIndent, false);
|
|
802
|
+
|
|
803
|
+
lines.push(...errorMessage.map(line => `${continuationIndent}${line}`));
|
|
804
|
+
lines.push(...errorDescription.map(line => `${continuationIndent}${line}`));
|
|
805
|
+
|
|
806
|
+
// Show original error FIRST (more important for debugging)
|
|
807
|
+
if (error.originalError) {
|
|
808
|
+
lines.push(separator);
|
|
809
|
+
lines.push(`${continuationIndent}ORIGINAL ERROR:`);
|
|
810
|
+
lines.push(separator);
|
|
811
|
+
|
|
812
|
+
const originalMessage = this.wrapText(`${error.originalError.name}: ${error.originalError.message}`, continuationIndent, false);
|
|
813
|
+
lines.push(...originalMessage.map(line => `${continuationIndent}${line}`));
|
|
814
|
+
|
|
815
|
+
if (error.originalError.stack) {
|
|
816
|
+
lines.push(`${continuationIndent}Stack trace:`);
|
|
817
|
+
const stackLines = this.formatStackTrace(error.originalError.stack, continuationIndent);
|
|
818
|
+
lines.push(...stackLines);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Then show A_Error stack trace
|
|
823
|
+
if (error.stack) {
|
|
824
|
+
lines.push(separator);
|
|
825
|
+
lines.push(`${continuationIndent}A_ERROR STACK:`);
|
|
826
|
+
lines.push(separator);
|
|
827
|
+
const stackLines = this.formatStackTrace(error.stack, continuationIndent);
|
|
828
|
+
lines.push(...stackLines);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Documentation link at the end
|
|
832
|
+
if (error.link) {
|
|
833
|
+
lines.push(separator);
|
|
834
|
+
const linkText = this.wrapText(`Documentation: ${error.link}`, continuationIndent, false);
|
|
835
|
+
lines.push(...linkText.map(line => `${continuationIndent}${line}`));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
lines.push(separator);
|
|
839
|
+
|
|
840
|
+
return lines.join('\n');
|
|
841
|
+
}
|
|
551
842
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
843
|
+
/**
|
|
844
|
+
* Format stack trace with proper terminal width wrapping and indentation
|
|
845
|
+
*
|
|
846
|
+
* @param stack - The stack trace string
|
|
847
|
+
* @param baseIndent - Base indentation for continuation lines
|
|
848
|
+
* @returns Array of formatted stack trace lines
|
|
849
|
+
*/
|
|
850
|
+
private formatStackTrace(stack: string, baseIndent: string): string[] {
|
|
851
|
+
const stackLines = stack.split('\n');
|
|
852
|
+
const formatted: string[] = [];
|
|
853
|
+
|
|
854
|
+
stackLines.forEach((line, index) => {
|
|
855
|
+
if (line.trim()) {
|
|
856
|
+
// Add extra indentation for stack trace lines
|
|
857
|
+
const stackIndent = index === 0 ? baseIndent : `${baseIndent} `;
|
|
858
|
+
const wrappedLines = this.wrapText(line.trim(), stackIndent, false);
|
|
859
|
+
formatted.push(...wrappedLines.map(wrappedLine =>
|
|
860
|
+
index === 0 && wrappedLine === wrappedLines[0]
|
|
861
|
+
? `${baseIndent}${wrappedLine}`
|
|
862
|
+
: `${baseIndent} ${wrappedLine}`
|
|
863
|
+
));
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
return formatted;
|
|
570
868
|
}
|
|
571
869
|
|
|
572
870
|
/**
|
|
573
871
|
* Format standard Error instances for inline display within compiled messages
|
|
574
872
|
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
873
|
+
* Provides clean, readable formatting for standard JavaScript errors with:
|
|
874
|
+
* - Terminal width aware message wrapping
|
|
875
|
+
* - Properly formatted stack traces
|
|
876
|
+
* - Consistent indentation with rest of logger
|
|
577
877
|
*
|
|
578
878
|
* @param error - The Error instance to format
|
|
579
879
|
* @returns Formatted string ready for display
|
|
580
880
|
*/
|
|
581
881
|
protected compile_Error(error: Error): string {
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
882
|
+
const continuationIndent = `${' '.repeat(this.STANDARD_SCOPE_LENGTH + 3)}${A_LOGGER_FORMAT.PIPE}`;
|
|
883
|
+
const separator = `${continuationIndent}-------------------------------`;
|
|
884
|
+
const lines: string[] = [];
|
|
885
|
+
|
|
886
|
+
// Add error header
|
|
887
|
+
lines.push('');
|
|
888
|
+
lines.push(separator);
|
|
889
|
+
lines.push(`${continuationIndent}ERROR: ${error.name}`);
|
|
890
|
+
lines.push(separator);
|
|
891
|
+
|
|
892
|
+
// Format and wrap error message
|
|
893
|
+
const errorMessage = this.wrapText(`Message: ${error.message}`, continuationIndent, false);
|
|
894
|
+
lines.push(...errorMessage.map(line => `${continuationIndent}${line}`));
|
|
895
|
+
|
|
896
|
+
// Format stack trace if available
|
|
897
|
+
if (error.stack) {
|
|
898
|
+
lines.push(separator);
|
|
899
|
+
lines.push(`${continuationIndent}STACK TRACE:`);
|
|
900
|
+
lines.push(separator);
|
|
901
|
+
const stackLines = this.formatStackTrace(error.stack, continuationIndent);
|
|
902
|
+
lines.push(...stackLines);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
lines.push(separator);
|
|
906
|
+
|
|
907
|
+
return lines.join('\n');
|
|
593
908
|
}
|
|
594
909
|
|
|
595
910
|
// =============================================
|
|
@@ -98,6 +98,19 @@ export const A_LOGGER_FORMAT = {
|
|
|
98
98
|
PIPE: '| '
|
|
99
99
|
} as const;
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Environment variable keys
|
|
103
|
+
*/
|
|
104
|
+
/**
|
|
105
|
+
* Terminal width configuration
|
|
106
|
+
*/
|
|
107
|
+
export const A_LOGGER_TERMINAL = {
|
|
108
|
+
DEFAULT_WIDTH: 80, // Default terminal width when can't be detected
|
|
109
|
+
MIN_WIDTH: 40, // Minimum width for formatted output
|
|
110
|
+
MAX_LINE_LENGTH_RATIO: 0.8, // Use 80% of terminal width for content
|
|
111
|
+
BROWSER_DEFAULT_WIDTH: 120 // Default width for browser console
|
|
112
|
+
} as const;
|
|
113
|
+
|
|
101
114
|
/**
|
|
102
115
|
* Environment variable keys
|
|
103
116
|
*/
|
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
export type A_LoggerLevel = 'debug' | 'info' | 'warn' | 'error' | 'all';
|
|
3
|
+
export type A_LoggerLevel = 'debug' | 'info' | 'warn' | 'error' | 'all';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Available color names for the logger
|
|
7
|
+
* Can be used as first parameter in logging methods to specify message color
|
|
8
|
+
*/
|
|
9
|
+
export type A_LoggerColorName =
|
|
10
|
+
| 'red' | 'yellow' | 'green' | 'blue' | 'cyan' | 'magenta' | 'gray'
|
|
11
|
+
| 'brightBlue' | 'brightCyan' | 'brightMagenta' | 'darkGray' | 'lightGray'
|
|
12
|
+
| 'indigo' | 'violet' | 'purple' | 'lavender' | 'skyBlue' | 'steelBlue'
|
|
13
|
+
| 'slateBlue' | 'deepBlue' | 'lightBlue' | 'periwinkle' | 'cornflower'
|
|
14
|
+
| 'powder' | 'charcoal' | 'silver' | 'smoke' | 'slate';
|