@sc4rfurryx/proteusjs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/API.md +438 -0
  2. package/FEATURES.md +286 -0
  3. package/LICENSE +21 -0
  4. package/README.md +645 -0
  5. package/dist/.tsbuildinfo +1 -0
  6. package/dist/proteus.cjs.js +16014 -0
  7. package/dist/proteus.cjs.js.map +1 -0
  8. package/dist/proteus.d.ts +3018 -0
  9. package/dist/proteus.esm.js +16005 -0
  10. package/dist/proteus.esm.js.map +1 -0
  11. package/dist/proteus.esm.min.js +8 -0
  12. package/dist/proteus.esm.min.js.map +1 -0
  13. package/dist/proteus.js +16020 -0
  14. package/dist/proteus.js.map +1 -0
  15. package/dist/proteus.min.js +8 -0
  16. package/dist/proteus.min.js.map +1 -0
  17. package/package.json +98 -0
  18. package/src/__tests__/mvp-integration.test.ts +518 -0
  19. package/src/accessibility/AccessibilityEngine.ts +2106 -0
  20. package/src/accessibility/ScreenReaderSupport.ts +444 -0
  21. package/src/accessibility/__tests__/ScreenReaderSupport.test.ts +435 -0
  22. package/src/animations/FLIPAnimationSystem.ts +491 -0
  23. package/src/compatibility/BrowserCompatibility.ts +1076 -0
  24. package/src/containers/BreakpointSystem.ts +347 -0
  25. package/src/containers/ContainerBreakpoints.ts +726 -0
  26. package/src/containers/ContainerManager.ts +370 -0
  27. package/src/containers/ContainerUnits.ts +336 -0
  28. package/src/containers/ContextIsolation.ts +394 -0
  29. package/src/containers/ElementQueries.ts +411 -0
  30. package/src/containers/SmartContainer.ts +536 -0
  31. package/src/containers/SmartContainers.ts +376 -0
  32. package/src/containers/__tests__/ContainerBreakpoints.test.ts +411 -0
  33. package/src/containers/__tests__/SmartContainers.test.ts +281 -0
  34. package/src/content/ResponsiveImages.ts +570 -0
  35. package/src/core/EventSystem.ts +147 -0
  36. package/src/core/MemoryManager.ts +321 -0
  37. package/src/core/PerformanceMonitor.ts +238 -0
  38. package/src/core/PluginSystem.ts +275 -0
  39. package/src/core/ProteusJS.test.ts +164 -0
  40. package/src/core/ProteusJS.ts +962 -0
  41. package/src/developer/PerformanceProfiler.ts +567 -0
  42. package/src/developer/VisualDebuggingTools.ts +656 -0
  43. package/src/developer/ZeroConfigSystem.ts +593 -0
  44. package/src/index.ts +35 -0
  45. package/src/integration.test.ts +227 -0
  46. package/src/layout/AdaptiveGrid.ts +429 -0
  47. package/src/layout/ContentReordering.ts +532 -0
  48. package/src/layout/FlexboxEnhancer.ts +406 -0
  49. package/src/layout/FlowLayout.ts +545 -0
  50. package/src/layout/SpacingSystem.ts +512 -0
  51. package/src/observers/IntersectionObserverPolyfill.ts +289 -0
  52. package/src/observers/ObserverManager.ts +299 -0
  53. package/src/observers/ResizeObserverPolyfill.ts +179 -0
  54. package/src/performance/BatchDOMOperations.ts +519 -0
  55. package/src/performance/CSSOptimizationEngine.ts +646 -0
  56. package/src/performance/CacheOptimizationSystem.ts +601 -0
  57. package/src/performance/EfficientEventHandler.ts +740 -0
  58. package/src/performance/LazyEvaluationSystem.ts +532 -0
  59. package/src/performance/MemoryManagementSystem.ts +497 -0
  60. package/src/performance/PerformanceMonitor.ts +931 -0
  61. package/src/performance/__tests__/BatchDOMOperations.test.ts +309 -0
  62. package/src/performance/__tests__/EfficientEventHandler.test.ts +268 -0
  63. package/src/performance/__tests__/PerformanceMonitor.test.ts +422 -0
  64. package/src/polyfills/BrowserPolyfills.ts +586 -0
  65. package/src/polyfills/__tests__/BrowserPolyfills.test.ts +328 -0
  66. package/src/test/setup.ts +115 -0
  67. package/src/theming/SmartThemeSystem.ts +591 -0
  68. package/src/types/index.ts +134 -0
  69. package/src/typography/ClampScaling.ts +356 -0
  70. package/src/typography/FluidTypography.ts +759 -0
  71. package/src/typography/LineHeightOptimization.ts +430 -0
  72. package/src/typography/LineHeightOptimizer.ts +326 -0
  73. package/src/typography/TextFitting.ts +355 -0
  74. package/src/typography/TypographicScale.ts +428 -0
  75. package/src/typography/VerticalRhythm.ts +369 -0
  76. package/src/typography/__tests__/FluidTypography.test.ts +432 -0
  77. package/src/typography/__tests__/LineHeightOptimization.test.ts +436 -0
  78. package/src/utils/Logger.ts +173 -0
  79. package/src/utils/debounce.ts +259 -0
  80. package/src/utils/performance.ts +371 -0
  81. package/src/utils/support.ts +106 -0
  82. package/src/utils/version.ts +24 -0
@@ -0,0 +1,436 @@
1
+ /**
2
+ * LineHeightOptimization Test Suite
3
+ * Comprehensive tests for line height optimization system
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { LineHeightOptimization, LineHeightConfig } from '../LineHeightOptimization';
8
+
9
+ // Mock ResizeObserver
10
+ global.ResizeObserver = vi.fn().mockImplementation((callback) => ({
11
+ observe: vi.fn(),
12
+ unobserve: vi.fn(),
13
+ disconnect: vi.fn(),
14
+ }));
15
+
16
+ describe('LineHeightOptimization', () => {
17
+ let lineHeightOptimization: LineHeightOptimization;
18
+ let testElement: HTMLElement;
19
+
20
+ beforeEach(() => {
21
+ // Clean up DOM
22
+ document.body.innerHTML = '';
23
+
24
+ // Create test element
25
+ testElement = document.createElement('p');
26
+ testElement.textContent = 'This is a test paragraph with some content to test line height optimization.';
27
+ testElement.style.fontSize = '16px';
28
+ document.body.appendChild(testElement);
29
+
30
+ lineHeightOptimization = new LineHeightOptimization();
31
+
32
+ // Mock getComputedStyle
33
+ vi.spyOn(window, 'getComputedStyle').mockReturnValue({
34
+ fontSize: '16px',
35
+ fontFamily: 'Arial, sans-serif'
36
+ } as CSSStyleDeclaration);
37
+
38
+ // Mock getBoundingClientRect
39
+ vi.spyOn(testElement, 'getBoundingClientRect').mockReturnValue({
40
+ width: 400,
41
+ height: 100,
42
+ top: 0,
43
+ left: 0,
44
+ bottom: 100,
45
+ right: 400,
46
+ x: 0,
47
+ y: 0,
48
+ toJSON: () => ({})
49
+ } as DOMRect);
50
+ });
51
+
52
+ afterEach(() => {
53
+ lineHeightOptimization.destroy();
54
+ document.body.innerHTML = '';
55
+ vi.restoreAllMocks();
56
+ });
57
+
58
+ describe('Basic Line Height Optimization', () => {
59
+ it('should optimize line height with default settings', () => {
60
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
61
+
62
+ expect(result.lineHeight).toBeGreaterThan(1);
63
+ expect(result.lineHeightCSS).toBeTruthy();
64
+ expect(result.reasoning).toBeInstanceOf(Array);
65
+ expect(result.reasoning.length).toBeGreaterThan(0);
66
+ expect(testElement.style.lineHeight).toBe(result.lineHeightCSS);
67
+ });
68
+
69
+ it('should apply different density settings', () => {
70
+ const compactResult = lineHeightOptimization.optimizeLineHeight(testElement, {
71
+ density: 'compact'
72
+ });
73
+
74
+ const spaciousResult = lineHeightOptimization.optimizeLineHeight(testElement, {
75
+ density: 'spacious'
76
+ });
77
+
78
+ expect(compactResult.lineHeight).toBeLessThan(spaciousResult.lineHeight);
79
+ });
80
+
81
+ it('should add debugging attributes', () => {
82
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
83
+
84
+ expect(testElement.getAttribute('data-proteus-line-height')).toBe(
85
+ result.lineHeight.toString()
86
+ );
87
+ expect(testElement.getAttribute('data-proteus-line-height-reasoning')).toBeTruthy();
88
+ });
89
+ });
90
+
91
+ describe('Content Type Adjustments', () => {
92
+ it('should adjust for heading content', () => {
93
+ const headingResult = lineHeightOptimization.optimizeLineHeight(testElement, {
94
+ contentType: 'heading'
95
+ });
96
+
97
+ const bodyResult = lineHeightOptimization.optimizeLineHeight(testElement, {
98
+ contentType: 'body'
99
+ });
100
+
101
+ expect(headingResult.lineHeight).toBeLessThan(bodyResult.lineHeight);
102
+ expect(headingResult.adjustments).toContain(
103
+ expect.stringContaining('Content type (heading)')
104
+ );
105
+ });
106
+
107
+ it('should adjust for code content', () => {
108
+ const codeResult = lineHeightOptimization.optimizeLineHeight(testElement, {
109
+ contentType: 'code'
110
+ });
111
+
112
+ const bodyResult = lineHeightOptimization.optimizeLineHeight(testElement, {
113
+ contentType: 'body'
114
+ });
115
+
116
+ expect(codeResult.lineHeight).toBeGreaterThan(bodyResult.lineHeight);
117
+ expect(codeResult.adjustments).toContain(
118
+ expect.stringContaining('Content type (code)')
119
+ );
120
+ });
121
+
122
+ it('should adjust for caption content', () => {
123
+ const captionResult = lineHeightOptimization.optimizeLineHeight(testElement, {
124
+ contentType: 'caption'
125
+ });
126
+
127
+ const bodyResult = lineHeightOptimization.optimizeLineHeight(testElement, {
128
+ contentType: 'body'
129
+ });
130
+
131
+ expect(captionResult.lineHeight).toBeLessThan(bodyResult.lineHeight);
132
+ });
133
+ });
134
+
135
+ describe('Language-Specific Adjustments', () => {
136
+ it('should adjust for Chinese language', () => {
137
+ const chineseResult = lineHeightOptimization.optimizeLineHeight(testElement, {
138
+ language: 'zh-CN'
139
+ });
140
+
141
+ const englishResult = lineHeightOptimization.optimizeLineHeight(testElement, {
142
+ language: 'en'
143
+ });
144
+
145
+ expect(chineseResult.lineHeight).toBeGreaterThan(englishResult.lineHeight);
146
+ expect(chineseResult.adjustments).toContain(
147
+ expect.stringContaining('Language (zh)')
148
+ );
149
+ });
150
+
151
+ it('should adjust for Japanese language', () => {
152
+ const japaneseResult = lineHeightOptimization.optimizeLineHeight(testElement, {
153
+ language: 'ja'
154
+ });
155
+
156
+ const englishResult = lineHeightOptimization.optimizeLineHeight(testElement, {
157
+ language: 'en'
158
+ });
159
+
160
+ expect(japaneseResult.lineHeight).toBeGreaterThan(englishResult.lineHeight);
161
+ });
162
+
163
+ it('should handle unknown languages gracefully', () => {
164
+ const unknownResult = lineHeightOptimization.optimizeLineHeight(testElement, {
165
+ language: 'unknown-lang'
166
+ });
167
+
168
+ expect(unknownResult.lineHeight).toBeGreaterThan(0);
169
+ expect(unknownResult.adjustments).not.toContain(
170
+ expect.stringContaining('Language (unknown-lang)')
171
+ );
172
+ });
173
+ });
174
+
175
+ describe('Line Length Adjustments', () => {
176
+ it('should adjust for very short lines', () => {
177
+ // Mock narrow container
178
+ vi.spyOn(testElement, 'getBoundingClientRect').mockReturnValue({
179
+ width: 100, // Very narrow
180
+ height: 100,
181
+ top: 0,
182
+ left: 0,
183
+ bottom: 100,
184
+ right: 100,
185
+ x: 0,
186
+ y: 0,
187
+ toJSON: () => ({})
188
+ } as DOMRect);
189
+
190
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
191
+
192
+ expect(result.adjustments).toContain(
193
+ expect.stringContaining('Line length')
194
+ );
195
+ });
196
+
197
+ it('should adjust for very long lines', () => {
198
+ // Mock very wide container
199
+ vi.spyOn(testElement, 'getBoundingClientRect').mockReturnValue({
200
+ width: 1200, // Very wide
201
+ height: 100,
202
+ top: 0,
203
+ left: 0,
204
+ bottom: 100,
205
+ right: 1200,
206
+ x: 0,
207
+ y: 0,
208
+ toJSON: () => ({})
209
+ } as DOMRect);
210
+
211
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
212
+
213
+ expect(result.adjustments).toContain(
214
+ expect.stringContaining('Line length')
215
+ );
216
+ });
217
+ });
218
+
219
+ describe('Font Size Adjustments', () => {
220
+ it('should adjust for small font sizes', () => {
221
+ vi.spyOn(window, 'getComputedStyle').mockReturnValue({
222
+ fontSize: '10px', // Very small
223
+ fontFamily: 'Arial, sans-serif'
224
+ } as CSSStyleDeclaration);
225
+
226
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
227
+
228
+ expect(result.adjustments).toContain(
229
+ expect.stringContaining('Font size (10px)')
230
+ );
231
+ });
232
+
233
+ it('should adjust for large font sizes', () => {
234
+ vi.spyOn(window, 'getComputedStyle').mockReturnValue({
235
+ fontSize: '32px', // Very large
236
+ fontFamily: 'Arial, sans-serif'
237
+ } as CSSStyleDeclaration);
238
+
239
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
240
+
241
+ expect(result.adjustments).toContain(
242
+ expect.stringContaining('Font size (32px)')
243
+ );
244
+ });
245
+ });
246
+
247
+ describe('Accessibility Compliance', () => {
248
+ it('should enforce WCAG AA compliance', () => {
249
+ const config: LineHeightConfig = {
250
+ density: 'compact', // Would normally result in low line height
251
+ accessibility: 'AA',
252
+ enforceAccessibility: true
253
+ };
254
+
255
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, config);
256
+
257
+ expect(result.lineHeight).toBeGreaterThanOrEqual(1.5); // WCAG AA minimum
258
+ expect(result.accessibilityCompliant).toBe(true);
259
+ });
260
+
261
+ it('should enforce WCAG AAA compliance', () => {
262
+ const config: LineHeightConfig = {
263
+ density: 'compact',
264
+ accessibility: 'AAA',
265
+ enforceAccessibility: true
266
+ };
267
+
268
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, config);
269
+
270
+ expect(result.lineHeight).toBeGreaterThanOrEqual(1.6); // WCAG AAA minimum
271
+ expect(result.accessibilityCompliant).toBe(true);
272
+ });
273
+
274
+ it('should allow bypassing accessibility constraints', () => {
275
+ const config: LineHeightConfig = {
276
+ density: 'compact',
277
+ accessibility: 'AA',
278
+ enforceAccessibility: false
279
+ };
280
+
281
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, config);
282
+
283
+ // Should not enforce minimum if disabled
284
+ expect(result.lineHeight).toBeLessThan(1.5);
285
+ });
286
+
287
+ it('should mark non-compliant results', () => {
288
+ const config: LineHeightConfig = {
289
+ density: 'compact',
290
+ accessibility: 'AAA',
291
+ enforceAccessibility: true
292
+ };
293
+
294
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, config);
295
+
296
+ if (result.lineHeight < 1.6) {
297
+ expect(result.accessibilityCompliant).toBe(false);
298
+ } else {
299
+ expect(result.accessibilityCompliant).toBe(true);
300
+ }
301
+ });
302
+ });
303
+
304
+ describe('User Preferences', () => {
305
+ it('should respect user line spacing preferences', () => {
306
+ // Mock CSS custom property for user preferences
307
+ vi.spyOn(window, 'getComputedStyle').mockImplementation((element) => {
308
+ if (element === document.documentElement) {
309
+ return {
310
+ getPropertyValue: (prop: string) => {
311
+ if (prop === '--user-line-spacing') return '1.2';
312
+ return '';
313
+ }
314
+ } as CSSStyleDeclaration;
315
+ }
316
+ return {
317
+ fontSize: '16px',
318
+ fontFamily: 'Arial, sans-serif'
319
+ } as CSSStyleDeclaration;
320
+ });
321
+
322
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, {
323
+ respectUserPreferences: true
324
+ });
325
+
326
+ expect(result.adjustments).toContain(
327
+ expect.stringContaining('User preferences')
328
+ );
329
+ });
330
+
331
+ it('should handle missing user preferences gracefully', () => {
332
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, {
333
+ respectUserPreferences: true
334
+ });
335
+
336
+ expect(result.lineHeight).toBeGreaterThan(0);
337
+ });
338
+ });
339
+
340
+ describe('Element Management', () => {
341
+ it('should update line height when element changes', () => {
342
+ const config: LineHeightConfig = {
343
+ density: 'comfortable'
344
+ };
345
+
346
+ lineHeightOptimization.optimizeLineHeight(testElement, config);
347
+ const initialLineHeight = testElement.style.lineHeight;
348
+
349
+ // Change element size
350
+ vi.spyOn(testElement, 'getBoundingClientRect').mockReturnValue({
351
+ width: 800, // Much wider
352
+ height: 100,
353
+ top: 0,
354
+ left: 0,
355
+ bottom: 100,
356
+ right: 800,
357
+ x: 0,
358
+ y: 0,
359
+ toJSON: () => ({})
360
+ } as DOMRect);
361
+
362
+ lineHeightOptimization.updateLineHeight(testElement);
363
+
364
+ expect(testElement.style.lineHeight).not.toBe(initialLineHeight);
365
+ });
366
+
367
+ it('should remove optimization', () => {
368
+ lineHeightOptimization.optimizeLineHeight(testElement);
369
+
370
+ expect(testElement.style.lineHeight).toBeTruthy();
371
+ expect(testElement.getAttribute('data-proteus-line-height')).toBeTruthy();
372
+
373
+ lineHeightOptimization.removeOptimization(testElement);
374
+
375
+ expect(testElement.style.lineHeight).toBeFalsy();
376
+ expect(testElement.getAttribute('data-proteus-line-height')).toBeNull();
377
+ });
378
+
379
+ it('should handle elements without optimization', () => {
380
+ expect(() => {
381
+ lineHeightOptimization.removeOptimization(testElement);
382
+ }).not.toThrow();
383
+
384
+ expect(() => {
385
+ lineHeightOptimization.updateLineHeight(testElement);
386
+ }).not.toThrow();
387
+ });
388
+ });
389
+
390
+ describe('Error Handling', () => {
391
+ it('should handle errors gracefully', () => {
392
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
393
+
394
+ // Force an error by providing invalid config
395
+ const config = null as any;
396
+
397
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, config);
398
+
399
+ expect(result.lineHeight).toBeGreaterThan(0);
400
+ expect(result.reasoning).toContain('Error occurred, using default');
401
+ expect(consoleSpy).toHaveBeenCalled();
402
+
403
+ consoleSpy.mockRestore();
404
+ });
405
+
406
+ it('should clean up resources on destroy', () => {
407
+ lineHeightOptimization.optimizeLineHeight(testElement);
408
+
409
+ expect(() => {
410
+ lineHeightOptimization.destroy();
411
+ }).not.toThrow();
412
+ });
413
+ });
414
+
415
+ describe('Precision and Rounding', () => {
416
+ it('should round line height to reasonable precision', () => {
417
+ const result = lineHeightOptimization.optimizeLineHeight(testElement);
418
+
419
+ // Should be rounded to 3 decimal places
420
+ const decimalPlaces = (result.lineHeight.toString().split('.')[1] || '').length;
421
+ expect(decimalPlaces).toBeLessThanOrEqual(3);
422
+ });
423
+
424
+ it('should provide detailed reasoning', () => {
425
+ const result = lineHeightOptimization.optimizeLineHeight(testElement, {
426
+ density: 'comfortable',
427
+ contentType: 'body',
428
+ language: 'en',
429
+ accessibility: 'AA'
430
+ });
431
+
432
+ expect(result.reasoning.length).toBeGreaterThan(1);
433
+ expect(result.reasoning[0]).toContain('comfortable density');
434
+ });
435
+ });
436
+ });
@@ -0,0 +1,173 @@
1
+ /**
2
+ * ProteusJS Logger
3
+ * Centralized logging system with configurable levels and production-safe output
4
+ */
5
+
6
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
7
+
8
+ export interface LoggerConfig {
9
+ level: LogLevel;
10
+ prefix: string;
11
+ enableInProduction: boolean;
12
+ enableTimestamps: boolean;
13
+ enableStackTrace: boolean;
14
+ }
15
+
16
+ export class Logger {
17
+ private static instance: Logger;
18
+ private config: LoggerConfig;
19
+ private readonly levels: Record<LogLevel, number> = {
20
+ debug: 0,
21
+ info: 1,
22
+ warn: 2,
23
+ error: 3,
24
+ silent: 4
25
+ };
26
+
27
+ private constructor(config: Partial<LoggerConfig> = {}) {
28
+ this.config = {
29
+ level: 'warn',
30
+ prefix: 'ProteusJS',
31
+ enableInProduction: false,
32
+ enableTimestamps: false,
33
+ enableStackTrace: false,
34
+ ...config
35
+ };
36
+ }
37
+
38
+ public static getInstance(config?: Partial<LoggerConfig>): Logger {
39
+ if (!Logger.instance) {
40
+ Logger.instance = new Logger(config);
41
+ }
42
+ return Logger.instance;
43
+ }
44
+
45
+ public static configure(config: Partial<LoggerConfig>): void {
46
+ if (Logger.instance) {
47
+ Logger.instance.config = { ...Logger.instance.config, ...config };
48
+ } else {
49
+ Logger.instance = new Logger(config);
50
+ }
51
+ }
52
+
53
+ private shouldLog(level: LogLevel): boolean {
54
+ // Don't log in production unless explicitly enabled
55
+ if (process.env['NODE_ENV'] === 'production' && !this.config.enableInProduction) {
56
+ return level === 'error'; // Only errors in production
57
+ }
58
+
59
+ return this.levels[level] >= this.levels[this.config.level];
60
+ }
61
+
62
+ private formatMessage(level: LogLevel, message: string, ...args: unknown[]): [string, ...unknown[]] {
63
+ let formattedMessage = message;
64
+
65
+ // Add prefix
66
+ if (this.config.prefix) {
67
+ formattedMessage = `${this.config.prefix}: ${formattedMessage}`;
68
+ }
69
+
70
+ // Add timestamp
71
+ if (this.config.enableTimestamps) {
72
+ const timestamp = new Date().toISOString();
73
+ formattedMessage = `[${timestamp}] ${formattedMessage}`;
74
+ }
75
+
76
+ // Add log level
77
+ const levelPrefix = level.toUpperCase().padEnd(5);
78
+ formattedMessage = `[${levelPrefix}] ${formattedMessage}`;
79
+
80
+ return [formattedMessage, ...args];
81
+ }
82
+
83
+ public debug(message: string, ...args: unknown[]): void {
84
+ if (!this.shouldLog('debug')) return;
85
+
86
+ const [formattedMessage, ...formattedArgs] = this.formatMessage('debug', message, ...args);
87
+ console.debug(formattedMessage, ...formattedArgs);
88
+
89
+ if (this.config.enableStackTrace) {
90
+ console.trace();
91
+ }
92
+ }
93
+
94
+ public info(message: string, ...args: unknown[]): void {
95
+ if (!this.shouldLog('info')) return;
96
+
97
+ const [formattedMessage, ...formattedArgs] = this.formatMessage('info', message, ...args);
98
+ console.info(formattedMessage, ...formattedArgs);
99
+ }
100
+
101
+ public warn(message: string, ...args: unknown[]): void {
102
+ if (!this.shouldLog('warn')) return;
103
+
104
+ const [formattedMessage, ...formattedArgs] = this.formatMessage('warn', message, ...args);
105
+ console.warn(formattedMessage, ...formattedArgs);
106
+ }
107
+
108
+ public error(message: string, error?: Error | unknown, ...args: unknown[]): void {
109
+ if (!this.shouldLog('error')) return;
110
+
111
+ const [formattedMessage, ...formattedArgs] = this.formatMessage('error', message, ...args);
112
+
113
+ if (error instanceof Error) {
114
+ console.error(formattedMessage, error, ...formattedArgs);
115
+ if (this.config.enableStackTrace && error.stack) {
116
+ console.error('Stack trace:', error.stack);
117
+ }
118
+ } else if (error) {
119
+ console.error(formattedMessage, error, ...formattedArgs);
120
+ } else {
121
+ console.error(formattedMessage, ...formattedArgs);
122
+ }
123
+ }
124
+
125
+ public group(label: string): void {
126
+ if (!this.shouldLog('info')) return;
127
+ console.group(`${this.config.prefix}: ${label}`);
128
+ }
129
+
130
+ public groupEnd(): void {
131
+ if (!this.shouldLog('info')) return;
132
+ console.groupEnd();
133
+ }
134
+
135
+ public time(label: string): void {
136
+ if (!this.shouldLog('debug')) return;
137
+ console.time(`${this.config.prefix}: ${label}`);
138
+ }
139
+
140
+ public timeEnd(label: string): void {
141
+ if (!this.shouldLog('debug')) return;
142
+ console.timeEnd(`${this.config.prefix}: ${label}`);
143
+ }
144
+
145
+ public setLevel(level: LogLevel): void {
146
+ this.config.level = level;
147
+ }
148
+
149
+ public getLevel(): LogLevel {
150
+ return this.config.level;
151
+ }
152
+
153
+ public isEnabled(level: LogLevel): boolean {
154
+ return this.shouldLog(level);
155
+ }
156
+ }
157
+
158
+ // Create default logger instance
159
+ export const logger = Logger.getInstance({
160
+ level: process.env['NODE_ENV'] === 'development' ? 'debug' : 'warn',
161
+ prefix: 'ProteusJS',
162
+ enableInProduction: false,
163
+ enableTimestamps: process.env['NODE_ENV'] === 'development',
164
+ enableStackTrace: false
165
+ });
166
+
167
+ // Convenience functions
168
+ export const debug = (message: string, ...args: unknown[]): void => logger.debug(message, ...args);
169
+ export const info = (message: string, ...args: unknown[]): void => logger.info(message, ...args);
170
+ export const warn = (message: string, ...args: unknown[]): void => logger.warn(message, ...args);
171
+ export const error = (message: string, error?: Error | unknown, ...args: unknown[]): void => logger.error(message, error, ...args);
172
+
173
+ export default logger;