Skip to content

Commit a626e74

Browse files
committed
refactor: modularize logging-utils.js (790 lines) into 5 modules
- Refactored logging-utils.js (790 lines) into modular architecture - Created 5 modules: dependency-loader, config-manager, basic-logger, ui-components, formatter-utils - Maintained 100% backward compatibility with original API - All 97 tests pass, validation script confirms compatibility - Main file reduced from 790 to 150 lines (81% reduction) - Modules focused on single responsibilities for better maintainability - Follows established refactoring pattern from previous utility refactorings
1 parent 64f31cb commit a626e74

8 files changed

Lines changed: 1865 additions & 713 deletions

File tree

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Basic Logger Module for LoggingUtils
4+
*
5+
* Core logging methods: error, warn, info, debug, success
6+
*/
7+
8+
class BasicLogger {
9+
constructor(dependencies, configManager) {
10+
this.dependencies = dependencies;
11+
this.configManager = configManager;
12+
}
13+
14+
/**
15+
* Generic log method
16+
*/
17+
log(level, message, ...args) {
18+
if (!this.configManager.shouldLog(level)) {
19+
return;
20+
}
21+
22+
const timestamp = this.configManager.formatTimestamp();
23+
const color = this.dependencies.colors[level] || ((s) => s);
24+
const prefix = this.getLevelPrefix(level);
25+
26+
// Format message with args
27+
let formattedMessage = message;
28+
if (args.length > 0) {
29+
try {
30+
formattedMessage = this.formatMessage(message, args);
31+
} catch (e) {
32+
// If formatting fails, just concatenate
33+
formattedMessage = `${message} ${args.join(' ')}`;
34+
}
35+
}
36+
37+
const output = `${timestamp}${prefix} ${color(formattedMessage)}`;
38+
39+
// Use appropriate console method
40+
if (level === 'error') {
41+
console.error(output);
42+
} else {
43+
console.log(output);
44+
}
45+
}
46+
47+
/**
48+
* Get prefix for log level
49+
*/
50+
getLevelPrefix(level) {
51+
const prefixes = {
52+
error: '✗',
53+
warn: '⚠',
54+
info: 'ℹ',
55+
debug: '🔍',
56+
success: '✓',
57+
};
58+
59+
return prefixes[level] || '•';
60+
}
61+
62+
/**
63+
* Format message with arguments
64+
*/
65+
formatMessage(message, args) {
66+
// Handle string substitution like console.log
67+
if (typeof message === 'string' && message.includes('%')) {
68+
return this.formatString(message, args);
69+
}
70+
71+
// Handle multiple arguments
72+
if (args.length === 0) {
73+
return message;
74+
}
75+
76+
// If message is not a string, convert everything to string
77+
const allArgs = [message, ...args];
78+
return allArgs
79+
.map((arg) => {
80+
if (typeof arg === 'object') {
81+
try {
82+
return JSON.stringify(arg, null, 2);
83+
} catch (e) {
84+
return String(arg);
85+
}
86+
}
87+
return String(arg);
88+
})
89+
.join(' ');
90+
}
91+
92+
/**
93+
* Format string with % substitutions
94+
*/
95+
formatString(format, args) {
96+
let i = 0;
97+
return format.replace(/%[sdifoO]/g, (match) => {
98+
if (i >= args.length) {
99+
return match;
100+
}
101+
102+
const arg = args[i++];
103+
switch (match) {
104+
case '%s':
105+
return String(arg);
106+
case '%d':
107+
case '%i':
108+
return Number(arg);
109+
case '%f':
110+
return parseFloat(arg);
111+
case '%o':
112+
case '%O':
113+
try {
114+
return JSON.stringify(arg, null, 2);
115+
} catch (e) {
116+
return String(arg);
117+
}
118+
default:
119+
return match;
120+
}
121+
});
122+
}
123+
124+
/**
125+
* Log error message
126+
*/
127+
error(message, ...args) {
128+
this.log('error', message, ...args);
129+
}
130+
131+
/**
132+
* Log warning message
133+
*/
134+
warn(message, ...args) {
135+
this.log('warn', message, ...args);
136+
}
137+
138+
/**
139+
* Log info message
140+
*/
141+
info(message, ...args) {
142+
this.log('info', message, ...args);
143+
}
144+
145+
/**
146+
* Log debug message
147+
*/
148+
debug(message, ...args) {
149+
this.log('debug', message, ...args);
150+
}
151+
152+
/**
153+
* Log success message
154+
*/
155+
success(message, ...args) {
156+
this.log('success', message, ...args);
157+
}
158+
159+
/**
160+
* Log with custom level
161+
*/
162+
custom(level, message, ...args) {
163+
this.log(level, message, ...args);
164+
}
165+
166+
/**
167+
* Log raw message without formatting
168+
*/
169+
raw(message) {
170+
console.log(message);
171+
}
172+
173+
/**
174+
* Log blank line
175+
*/
176+
blank() {
177+
console.log();
178+
}
179+
180+
/**
181+
* Log separator line
182+
*/
183+
separator(length = 40) {
184+
const line = '─'.repeat(length);
185+
console.log(line);
186+
}
187+
188+
/**
189+
* Log with indentation
190+
*/
191+
indent(message, level = 1, ...args) {
192+
const spaces = ' '.repeat(level);
193+
const formattedMessage = this.formatMessage(message, args);
194+
console.log(`${spaces}${formattedMessage}`);
195+
}
196+
}
197+
198+
module.exports = BasicLogger;

0 commit comments

Comments
 (0)