chromalogger 1.1.1 → 1.1.2

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.
@@ -9,9 +9,10 @@ import { isObject } from '../utils/validate.js';
9
9
  * Format an object for display
10
10
  * @param {Object} obj - Object to format
11
11
  * @param {number} [depth=0] - Current depth for indentation
12
+ * @param {Set} [refs] - Set to track circular references
12
13
  * @returns {string} Formatted object string
13
14
  */
14
- export const formatObject = (obj, depth = 0) => {
15
+ export const formatObject = (obj, depth = 0, refs = new WeakSet()) => {
15
16
  const indent = ' '.repeat(depth);
16
17
  const nextIndent = ' '.repeat(depth + 1);
17
18
 
@@ -20,24 +21,40 @@ export const formatObject = (obj, depth = 0) => {
20
21
  if (obj === undefined) return 'undefined';
21
22
  if (!isObject(obj)) return String(obj);
22
23
 
24
+ // Vérifier les références circulaires
25
+ if (refs.has(obj)) {
26
+ return '[Circular]';
27
+ }
28
+
29
+ // Marquer cet objet comme visité
30
+ refs.add(obj);
31
+
23
32
  const entries = Object.entries(obj);
24
33
  if (entries.length === 0) return '{}';
25
34
 
26
35
  // For small objects, keep on one line
27
36
  if (entries.every(([_, value]) => !isObject(value) || value === null)) {
28
37
  const content = entries
29
- .map(([key, value]) => `${key}: ${formatValue(value, depth + 1)}`)
38
+ .map(([key, value]) => `${key}: ${formatValue(value, depth + 1, refs)}`)
30
39
  .join(', ');
31
40
  return `{ ${content} }`;
32
41
  }
33
42
 
34
43
  // For larger or complex objects, use multiple lines
35
44
  const content = entries
36
- .map(([key, value]) => `${nextIndent}${key}: ${formatValue(value, depth + 1)}`)
45
+ .map(([key, value]) => `${nextIndent}${key}: ${formatValue(value, depth + 1, refs)}`)
37
46
  .join(',\n');
38
47
 
39
- return `{\n${content}\n${indent}}`;
48
+ const result = `{\n${content}\n${indent}}`;
49
+
50
+ // Nettoyer les références après le formatage
51
+ refs.delete(obj);
52
+ return result;
40
53
  } catch (error) {
54
+ // En cas d'erreur, nettoyer les références
55
+ if (isObject(obj)) {
56
+ refs.delete(obj);
57
+ }
41
58
  return '[Object]';
42
59
  }
43
60
  };
@@ -46,9 +63,10 @@ export const formatObject = (obj, depth = 0) => {
46
63
  * Format a value for display
47
64
  * @param {*} value - Value to format
48
65
  * @param {number} [depth=0] - Current depth for indentation
66
+ * @param {Set} [refs] - Set to track circular references
49
67
  * @returns {string} Formatted value
50
68
  */
51
- const formatValue = (value, depth = 0) => {
69
+ const formatValue = (value, depth = 0, refs = new WeakSet()) => {
52
70
  if (value === null) return 'null';
53
71
  if (value === undefined) return 'undefined';
54
72
 
@@ -57,9 +75,9 @@ const formatValue = (value, depth = 0) => {
57
75
  return `"${value}"`;
58
76
  case 'object':
59
77
  if (Array.isArray(value)) {
60
- return formatArray(value, depth);
78
+ return formatArray(value, depth, refs);
61
79
  }
62
- return formatObject(value, depth);
80
+ return formatObject(value, depth, refs);
63
81
  case 'function':
64
82
  return '[Function]';
65
83
  case 'symbol':
@@ -73,24 +91,37 @@ const formatValue = (value, depth = 0) => {
73
91
  * Format an array for display
74
92
  * @param {Array} arr - Array to format
75
93
  * @param {number} [depth=0] - Current depth for indentation
94
+ * @param {Set} [refs] - Set to track circular references
76
95
  * @returns {string} Formatted array string
77
96
  */
78
- const formatArray = (arr, depth = 0) => {
97
+ const formatArray = (arr, depth = 0, refs = new WeakSet()) => {
79
98
  if (!Array.isArray(arr)) return '[]';
80
99
  if (arr.length === 0) return '[]';
81
100
 
101
+ // Vérifier les références circulaires pour les tableaux
102
+ if (refs.has(arr)) {
103
+ return '[Circular]';
104
+ }
105
+
106
+ // Marquer ce tableau comme visité
107
+ refs.add(arr);
108
+
82
109
  const indent = ' '.repeat(depth);
83
110
  const nextIndent = ' '.repeat(depth + 1);
84
111
 
85
112
  // For small arrays, keep on one line
86
113
  if (arr.length <= 3 && arr.every((item) => !isObject(item) || item === null)) {
87
- return `[ ${arr.map((item) => formatValue(item, depth + 1)).join(', ')} ]`;
114
+ return `[ ${arr.map((item) => formatValue(item, depth + 1, refs)).join(', ')} ]`;
88
115
  }
89
116
 
90
117
  // For larger or complex arrays, use multiple lines
91
- const items = arr.map((item) => `${nextIndent}${formatValue(item, depth + 1)}`).join(',\n');
118
+ const items = arr.map((item) => `${nextIndent}${formatValue(item, depth + 1, refs)}`).join(',\n');
119
+
120
+ const result = `[\n${items}\n${indent}]`;
92
121
 
93
- return `[\n${items}\n${indent}]`;
122
+ // Nettoyer les références après le formatage
123
+ refs.delete(arr);
124
+ return result;
94
125
  };
95
126
 
96
127
  export default {
@@ -3,9 +3,9 @@
3
3
  * @module core/loggers/consoleLogger
4
4
  */
5
5
 
6
- import { formatObject } from '../formatters/objectFormatter.js';
7
6
  import { validateInput } from '../utils/validate.js';
8
7
  import styles from '../styles.js';
8
+ import util from 'util';
9
9
 
10
10
  /**
11
11
  * Log levels and their priorities
@@ -44,6 +44,9 @@ const createLogger = (...styleNames) => {
44
44
  */
45
45
  const logger = (...args) => {
46
46
  try {
47
+ console.log('\n=== DEBUG: Début de la fonction logger ===');
48
+ console.log('Arguments reçus:', args);
49
+
47
50
  // Vérifier le niveau de log
48
51
  let logLevel = LOG_LEVELS.INFO;
49
52
  if (styleNames.includes('dim')) {
@@ -54,30 +57,57 @@ const createLogger = (...styleNames) => {
54
57
  logLevel = LOG_LEVELS.ERROR;
55
58
  }
56
59
 
60
+ console.log('Niveau de log actuel:', currentLogLevel, 'Niveau requis:', logLevel);
61
+
57
62
  if (logLevel < currentLogLevel) return;
58
63
 
59
- const validArgs = validateInput(args);
64
+ // Si pas d'arguments, afficher une ligne vide
65
+ if (args.length === 0) {
66
+ console.log();
67
+ return;
68
+ }
69
+
70
+ // Préparer le message final
71
+ let output = '';
60
72
 
61
- // Handle template strings
62
- if (typeof validArgs[0] === 'string' && validArgs.length > 1) {
63
- const message = formatMessage(validArgs[0], validArgs.slice(1));
64
- console.log(`${stylePrefix}${message}${styles.reset}`);
73
+ // Si le premier argument est une chaîne et qu'il y a plus d'un argument,
74
+ // traiter comme un template string
75
+ if (typeof args[0] === 'string' && args.length > 1) {
76
+ const message = args[0];
77
+ const values = args.slice(1);
78
+ output = formatMessage(message, values);
65
79
  } else {
66
- // Format each argument
67
- const formattedArgs = validArgs.map((arg) => {
68
- if (arg === null) return 'null';
69
- if (arg === undefined) return 'undefined';
70
- if (typeof arg === 'object' || Array.isArray(arg)) {
71
- return formatObject(arg);
80
+ // Sinon, formater chaque argument individuellement
81
+ const formattedArgs = args.map((arg) => {
82
+ try {
83
+ if (arg === null) return 'null';
84
+ if (arg === undefined) return 'undefined';
85
+ if (typeof arg === 'object' || Array.isArray(arg)) {
86
+ return util.inspect(arg, {
87
+ showHidden: false,
88
+ depth: 6,
89
+ colors: false,
90
+ maxArrayLength: 10,
91
+ breakLength: 80,
92
+ compact: 3,
93
+ sorted: false,
94
+ getters: false,
95
+ showProxy: false,
96
+ customInspect: true,
97
+ });
98
+ }
99
+ return String(arg);
100
+ } catch (e) {
101
+ return `[Error: ${e.message}]`;
72
102
  }
73
- if (typeof arg === 'string') return arg;
74
- return String(arg);
75
103
  });
76
-
77
- // Handle multi-line output
78
- const output = formattedArgs.join(' ').split('\n').join('\n ');
79
- console.log(`${stylePrefix}${output}${styles.reset}`);
104
+ output = formattedArgs.join(' ');
80
105
  }
106
+
107
+ // Afficher le message formaté avec les styles
108
+ const finalOutput = stylePrefix + output + styles.reset;
109
+ console.log('=== DEBUG: Sortie finale ===\n', finalOutput, '\n======================');
110
+ console.log(finalOutput);
81
111
  } catch (error) {
82
112
  console.error(`${styles.red}LogColor: Logging error - ${error.message}${styles.reset}`);
83
113
  }
@@ -100,20 +130,55 @@ const createLogger = (...styleNames) => {
100
130
  * @returns {string} Formatted message
101
131
  */
102
132
  const formatMessage = (message, values = []) => {
103
- if (typeof message !== 'string' || !Array.isArray(values)) {
104
- return String(message);
133
+ if (typeof message !== 'string') {
134
+ return '';
105
135
  }
106
136
 
107
- return message.replace(/\{(\d+)\}/g, (match, index) => {
137
+ if (!Array.isArray(values) || values.length === 0) {
138
+ // Remplacer les doubles accolades échappées par des marqueurs temporaires
139
+ return message.replace(/\{\{/g, '\uE000').replace(/\}\}/g, '\uE001')
140
+ .replace(/\{\d+\}/g, match => match) // Laisser les placeholders tels quels
141
+ .replace(/\uE000/g, '{').replace(/\uE001/g, '}');
142
+ }
143
+
144
+ // Si le message ne contient pas de placeholders, ajouter les valeurs à la suite
145
+ if (!/\{\d+\}/.test(message)) {
146
+ return `${message} ${values
147
+ .map((v) => (typeof v === 'object' ? JSON.stringify(v) : String(v)))
148
+ .join(' ')}`.trim();
149
+ }
150
+
151
+ // Remplacer d'abord les doubles accolades échappées par des marqueurs temporaires
152
+ const tempMessage = message.replace(/\{\{/g, '\uE000').replace(/\}\}/g, '\uE001');
153
+
154
+ // Remplacer les placeholders
155
+ const formatted = tempMessage.replace(/\{(\d+)\}/g, (match, index) => {
108
156
  const value = values[parseInt(index, 10)];
109
- if (value === undefined) return match;
157
+ if (value === undefined || value === null) {
158
+ return match;
159
+ }
110
160
 
161
+ // Utiliser util.inspect pour les objets et tableaux
111
162
  if (typeof value === 'object' || Array.isArray(value)) {
112
- return formatObject(value);
163
+ return util.inspect(value, {
164
+ showHidden: false,
165
+ depth: 6,
166
+ colors: false,
167
+ maxArrayLength: 10,
168
+ breakLength: 80,
169
+ compact: 3,
170
+ sorted: false,
171
+ getters: false,
172
+ showProxy: false,
173
+ customInspect: true,
174
+ });
113
175
  }
114
176
 
115
177
  return String(value);
116
178
  });
179
+
180
+ // Remplacer les marqueurs temporaires par des accolades simples
181
+ return formatted.replace(/\uE000/g, '{').replace(/\uE001/g, '}');
117
182
  };
118
183
 
119
184
  /**
@@ -10,11 +10,14 @@
10
10
  * @throws {Error} If no arguments are provided
11
11
  */
12
12
  export const validateInput = (args) => {
13
- if (args.length === 0) {
14
- throw new Error('No arguments provided');
13
+ if (!args || args.length === 0) {
14
+ return [];
15
15
  }
16
16
 
17
- return args;
17
+ // Convertir les arguments en tableau s'ils ne le sont pas déjà
18
+ const argsArray = Array.isArray(args) ? args : Array.from(args);
19
+
20
+ return argsArray;
18
21
  };
19
22
 
20
23
  /**
package/index.js CHANGED
@@ -24,78 +24,38 @@ import {
24
24
  } from './core/loggers/consoleLogger.js';
25
25
  import { formatObject } from './core/formatters/objectFormatter.js';
26
26
 
27
- /**
28
- * Logger de base sans style particulier
29
- * @type {Function}
30
- */
27
+ // Créer les loggers avec leurs styles respectifs
31
28
  const log = createLogger();
32
-
33
- /**
34
- * Logger pour les messages de débogage (style atténué)
35
- * @type {Function}
36
- */
37
29
  const debug = createLogger('dim');
38
-
39
- /**
40
- * Logger pour les messages informatifs (style cyan)
41
- * @type {Function}
42
- */
43
30
  const info = createLogger('cyan');
44
-
45
- /**
46
- * Logger pour les avertissements (style jaune)
47
- * @type {Function}
48
- */
49
31
  const warn = createLogger('yellow');
32
+ const error = createLogger('red');
50
33
 
51
34
  /**
52
- * Logger pour les erreurs (style rouge)
53
- * @type {Function}
35
+ * ChromaLog - A powerful console logger with rich formatting and styling
54
36
  */
55
- const error = createLogger('red');
56
-
57
- // Export par défaut avec toutes les fonctionnalités
58
37
  const ChromaLog = {
59
38
  // Core
60
39
  styles,
61
-
62
- // Main logger methods
63
40
  createLogger,
64
41
  formatMessage,
65
42
  formatObject,
66
43
  setLogLevel,
67
-
68
- // Log levels
69
- LOG_LEVELS,
70
-
71
- // Pre-configured loggers
72
- log,
73
- debug,
74
- info,
75
- warn,
76
- error,
44
+ LOG_LEVELS: { ...LOG_LEVELS },
45
+
46
+ // Loggers
47
+ log: (...args) => log(...args),
48
+ debug: (...args) => debug(...args),
49
+ info: (...args) => info(...args),
50
+ warn: (...args) => warn(...args),
51
+ error: (...args) => error(...args),
77
52
  };
78
53
 
79
- export default ChromaLog;
54
+ // Exporter les loggers individuellement
55
+ export { log, debug, info, warn, error };
80
56
 
81
- // Export nommé pour l'import déstructuré
82
- export {
83
- // Core
84
- styles,
57
+ // Exporter les fonctions utilitaires
58
+ export { styles, createLogger, formatMessage, formatObject, setLogLevel, LOG_LEVELS };
85
59
 
86
- // Main logger methods
87
- createLogger,
88
- formatMessage,
89
- formatObject,
90
- setLogLevel,
91
-
92
- // Log levels
93
- LOG_LEVELS,
94
-
95
- // Pre-configured loggers
96
- log,
97
- debug,
98
- info,
99
- warn,
100
- error,
101
- };
60
+ // Exporter par défaut l'objet ChromaLog
61
+ export default ChromaLog;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chromalogger",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "A colorful and flexible console logger for Node.js with CLI support",
5
5
  "main": "chromalog.js",
6
6
  "type": "module",
@@ -49,6 +49,9 @@
49
49
  "engines": {
50
50
  "node": ">=12.0.0"
51
51
  },
52
+ "dependencies": {
53
+ "util": "^0.12.5"
54
+ },
52
55
  "devDependencies": {
53
56
  "c8": "^10.1.3",
54
57
  "eslint": "^8.0.0",
package/test.js CHANGED
@@ -4,10 +4,7 @@
4
4
  */
5
5
 
6
6
  // Import du module principal Chromalog
7
- import chromalog from './index.js';
8
-
9
- // Alias pour les propriétés
10
- const { createLogger, setLogLevel, log, debug, info, warn, error } = chromalog;
7
+ import { createLogger, setLogLevel, log, debug, info, warn, error } from './index.js';
11
8
 
12
9
  // ========================================
13
10
  // 1. Test des styles de base
@@ -65,7 +62,7 @@ info('Utilisateur:', utilisateur);
65
62
  console.log('\n=== 4. Test des templates ===');
66
63
  const nom = 'Alice';
67
64
  const age = 31;
68
- info('Bonjour {0}, vous avez {1} ans', nom, age);
65
+ info('Bonjour {0}, vous avez {1} ans de {{nom et age}}', nom, age);
69
66
 
70
67
  // ========================================
71
68
  // 5. Test des niveaux de log
@@ -127,4 +124,36 @@ console.log(
127
124
  )
128
125
  );
129
126
 
127
+ // Références circulaires
128
+ console.log('\n=== 6. Test des références circulaires ===');
129
+ const obj1 = { name: 'Objet 1' };
130
+ const obj2 = { name: 'Objet 2', ref: obj1 };
131
+ obj1.ref = obj2;
132
+
133
+ // Afficher directement l'objet pour le débogage
134
+ console.log('Obj1:', obj1);
135
+ console.log('Obj2:', obj2);
136
+
137
+ // Afficher avec le logger personnalisé
138
+ console.log('\n=== Test du logger personnalisé ===');
139
+ console.log('Type de log:', typeof log);
140
+ console.log('log est une fonction ?:', typeof log === 'function');
141
+
142
+ // Définir le niveau de log sur DEBUG pour voir tous les messages
143
+ setLogLevel('DEBUG');
144
+ console.log('Niveau de log défini sur DEBUG');
145
+
146
+ // Tester avec un simple message
147
+ console.log('\nTest avec un message simple:');
148
+ log('Ceci est un test simple');
149
+
150
+ // Tester avec un objet simple
151
+ console.log('\nTest avec un objet simple:');
152
+ log({ test: 'objet simple' });
153
+
154
+ // Tester avec les objets circulaires
155
+ log('\nTest avec les objets circulaires:');
156
+ log('obj1:', obj1);
157
+ log('obj2:', obj2);
158
+
130
159
  console.log('\n=== Fin des tests ===');