pulse-js-framework 1.7.4 → 1.7.5

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/runtime/logger.js CHANGED
@@ -2,6 +2,12 @@
2
2
  * Pulse Logger - Centralized logging with namespaces and levels
3
3
  * @module pulse-js-framework/runtime/logger
4
4
  *
5
+ * Automatically uses noop logging in production for zero overhead.
6
+ * Production mode is detected via:
7
+ * - process.env.NODE_ENV === 'production'
8
+ * - __PULSE_PROD__ global (for bundlers)
9
+ * - Manual configuration via configureLogger({ production: true })
10
+ *
5
11
  * @example
6
12
  * import { logger, createLogger } from './logger.js';
7
13
  *
@@ -13,7 +19,64 @@
13
19
  * // Namespaced logger
14
20
  * const log = createLogger('Router');
15
21
  * log.info('Navigating to /home'); // [Router] Navigating to /home
22
+ *
23
+ * // Force production mode (noop logging)
24
+ * configureLogger({ production: true });
25
+ */
26
+
27
+ // ============================================================================
28
+ // Environment Detection
29
+ // ============================================================================
30
+
31
+ /**
32
+ * Detect if we're in production mode
33
+ * @private
16
34
  */
35
+ function detectProduction() {
36
+ // Check for bundler-injected global
37
+ if (typeof __PULSE_PROD__ !== 'undefined') {
38
+ return __PULSE_PROD__;
39
+ }
40
+ // Check Node.js environment
41
+ if (typeof process !== 'undefined' && process.env) {
42
+ return process.env.NODE_ENV === 'production';
43
+ }
44
+ // Default to development
45
+ return false;
46
+ }
47
+
48
+ /** @type {boolean} */
49
+ let isProduction = detectProduction();
50
+
51
+ /**
52
+ * Configure logger behavior
53
+ * @param {Object} options - Configuration options
54
+ * @param {boolean} [options.production] - Force production mode (noop logging)
55
+ * @returns {void}
56
+ * @example
57
+ * // Disable all logging
58
+ * configureLogger({ production: true });
59
+ *
60
+ * // Re-enable logging
61
+ * configureLogger({ production: false });
62
+ */
63
+ export function configureLogger(options = {}) {
64
+ if (options.production !== undefined) {
65
+ isProduction = options.production;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Check if logger is in production mode
71
+ * @returns {boolean} True if production mode is active
72
+ */
73
+ export function isProductionMode() {
74
+ return isProduction;
75
+ }
76
+
77
+ // ============================================================================
78
+ // Log Levels
79
+ // ============================================================================
17
80
 
18
81
  /**
19
82
  * Log level constants
@@ -76,7 +139,7 @@ export function setLogLevel(level) {
76
139
  * }
77
140
  */
78
141
  export function getLogLevel() {
79
- return globalLevel;
142
+ return isProduction ? LogLevel.SILENT : globalLevel;
80
143
  }
81
144
 
82
145
  /**
@@ -94,6 +157,36 @@ export function setFormatter(formatter) {
94
157
  globalFormatter = formatter;
95
158
  }
96
159
 
160
+ // ============================================================================
161
+ // Production Noop Logger
162
+ // ============================================================================
163
+
164
+ /**
165
+ * Noop function for production builds
166
+ * @private
167
+ */
168
+ const noop = () => {};
169
+
170
+ /**
171
+ * Noop logger for production builds - zero overhead
172
+ * @private
173
+ * @type {Logger}
174
+ */
175
+ const noopLogger = {
176
+ error: noop,
177
+ warn: noop,
178
+ info: noop,
179
+ debug: noop,
180
+ group: noop,
181
+ groupEnd: noop,
182
+ log: noop,
183
+ child: () => noopLogger
184
+ };
185
+
186
+ // ============================================================================
187
+ // Development Logger Implementation
188
+ // ============================================================================
189
+
97
190
  /**
98
191
  * Format message arguments with optional namespace prefix
99
192
  * @private
@@ -132,37 +225,21 @@ function formatArgs(namespace, args) {
132
225
  */
133
226
 
134
227
  /**
135
- * Create a logger instance with optional namespace
136
- * @param {string|null} [namespace=null] - Logger namespace (e.g., 'Router', 'Store')
137
- * @param {LoggerOptions} [options={}] - Logger configuration options
138
- * @returns {Logger} A logger instance with error, warn, info, debug methods
139
- * @example
140
- * const log = createLogger('MyComponent');
141
- * log.info('Initialized'); // [MyComponent] Initialized
142
- * log.error('Failed', { code: 500 }); // [MyComponent] Failed { code: 500 }
143
- *
144
- * // With custom level
145
- * const debugLog = createLogger('Debug', { level: LogLevel.DEBUG });
228
+ * Create a development logger instance
229
+ * @private
230
+ * @param {string|null} namespace
231
+ * @param {LoggerOptions} options
232
+ * @returns {Logger}
146
233
  */
147
- export function createLogger(namespace = null, options = {}) {
234
+ function createDevLogger(namespace, options) {
148
235
  const localLevel = options.level;
149
236
 
150
- /**
151
- * Check if a message at the given level should be logged
152
- * @param {number} level - The log level to check
153
- * @returns {boolean} True if the message should be logged
154
- */
155
237
  function shouldLog(level) {
156
238
  const effectiveLevel = localLevel !== undefined ? localLevel : globalLevel;
157
239
  return level <= effectiveLevel;
158
240
  }
159
241
 
160
242
  return {
161
- /**
162
- * Log an error message (shown unless level is SILENT)
163
- * @param {...*} args - Values to log
164
- * @returns {void}
165
- */
166
243
  error(...args) {
167
244
  if (shouldLog(LogLevel.ERROR)) {
168
245
  if (globalFormatter) {
@@ -173,11 +250,6 @@ export function createLogger(namespace = null, options = {}) {
173
250
  }
174
251
  },
175
252
 
176
- /**
177
- * Log a warning message (shown at WARN level and above)
178
- * @param {...*} args - Values to log
179
- * @returns {void}
180
- */
181
253
  warn(...args) {
182
254
  if (shouldLog(LogLevel.WARN)) {
183
255
  if (globalFormatter) {
@@ -188,11 +260,6 @@ export function createLogger(namespace = null, options = {}) {
188
260
  }
189
261
  },
190
262
 
191
- /**
192
- * Log an info message (shown at INFO level and above)
193
- * @param {...*} args - Values to log
194
- * @returns {void}
195
- */
196
263
  info(...args) {
197
264
  if (shouldLog(LogLevel.INFO)) {
198
265
  if (globalFormatter) {
@@ -203,11 +270,6 @@ export function createLogger(namespace = null, options = {}) {
203
270
  }
204
271
  },
205
272
 
206
- /**
207
- * Log a debug message (only shown at DEBUG level)
208
- * @param {...*} args - Values to log
209
- * @returns {void}
210
- */
211
273
  debug(...args) {
212
274
  if (shouldLog(LogLevel.DEBUG)) {
213
275
  if (globalFormatter) {
@@ -218,33 +280,18 @@ export function createLogger(namespace = null, options = {}) {
218
280
  }
219
281
  },
220
282
 
221
- /**
222
- * Start a collapsed log group (only shown at DEBUG level)
223
- * @param {string} label - The group label
224
- * @returns {void}
225
- */
226
283
  group(label) {
227
284
  if (shouldLog(LogLevel.DEBUG)) {
228
285
  console.group(namespace ? `${formatNamespace(namespace)} ${label}` : label);
229
286
  }
230
287
  },
231
288
 
232
- /**
233
- * End the current log group
234
- * @returns {void}
235
- */
236
289
  groupEnd() {
237
290
  if (shouldLog(LogLevel.DEBUG)) {
238
291
  console.groupEnd();
239
292
  }
240
293
  },
241
294
 
242
- /**
243
- * Log a message at a custom level
244
- * @param {number} level - The LogLevel to use
245
- * @param {...*} args - Values to log
246
- * @returns {void}
247
- */
248
295
  log(level, ...args) {
249
296
  if (shouldLog(level)) {
250
297
  const formatted = formatArgs(namespace, args);
@@ -261,15 +308,6 @@ export function createLogger(namespace = null, options = {}) {
261
308
  }
262
309
  },
263
310
 
264
- /**
265
- * Create a child logger with an additional namespace segment
266
- * @param {string} childNamespace - The child namespace to append
267
- * @returns {Logger} A new logger with combined namespace
268
- * @example
269
- * const log = createLogger('App');
270
- * const routerLog = log.child('Router');
271
- * routerLog.info('Navigate'); // [App:Router] Navigate
272
- */
273
311
  child(childNamespace) {
274
312
  const combined = namespace
275
313
  ? `${namespace}${NAMESPACE_SEPARATOR}${childNamespace}`
@@ -279,8 +317,41 @@ export function createLogger(namespace = null, options = {}) {
279
317
  };
280
318
  }
281
319
 
320
+ // ============================================================================
321
+ // Public API
322
+ // ============================================================================
323
+
324
+ /**
325
+ * Create a logger instance with optional namespace
326
+ *
327
+ * In production mode, returns a noop logger with zero overhead.
328
+ * In development mode, returns a full-featured logger.
329
+ *
330
+ * @param {string|null} [namespace=null] - Logger namespace (e.g., 'Router', 'Store')
331
+ * @param {LoggerOptions} [options={}] - Logger configuration options
332
+ * @returns {Logger} A logger instance with error, warn, info, debug methods
333
+ * @example
334
+ * const log = createLogger('MyComponent');
335
+ * log.info('Initialized'); // [MyComponent] Initialized
336
+ * log.error('Failed', { code: 500 }); // [MyComponent] Failed { code: 500 }
337
+ *
338
+ * // With custom level
339
+ * const debugLog = createLogger('Debug', { level: LogLevel.DEBUG });
340
+ */
341
+ export function createLogger(namespace = null, options = {}) {
342
+ // Return noop logger in production for zero overhead
343
+ if (isProduction) {
344
+ return noopLogger;
345
+ }
346
+ return createDevLogger(namespace, options);
347
+ }
348
+
282
349
  /**
283
350
  * Default logger instance without namespace
351
+ *
352
+ * Note: This is evaluated at module load time. If you configure
353
+ * production mode after import, use createLogger() instead.
354
+ *
284
355
  * @type {Logger}
285
356
  * @example
286
357
  * import { logger } from './logger.js';
@@ -290,6 +361,10 @@ export const logger = createLogger();
290
361
 
291
362
  /**
292
363
  * Pre-configured loggers for common Pulse subsystems
364
+ *
365
+ * These are lazily evaluated on first access to respect
366
+ * production mode configuration.
367
+ *
293
368
  * @type {Object.<string, Logger>}
294
369
  * @property {Logger} pulse - Logger for core reactivity system
295
370
  * @property {Logger} dom - Logger for DOM operations
@@ -300,13 +375,13 @@ export const logger = createLogger();
300
375
  * @property {Logger} cli - Logger for CLI tools
301
376
  */
302
377
  export const loggers = {
303
- pulse: createLogger('Pulse'),
304
- dom: createLogger('DOM'),
305
- router: createLogger('Router'),
306
- store: createLogger('Store'),
307
- native: createLogger('Native'),
308
- hmr: createLogger('HMR'),
309
- cli: createLogger('CLI')
378
+ get pulse() { return isProduction ? noopLogger : createDevLogger('Pulse', {}); },
379
+ get dom() { return isProduction ? noopLogger : createDevLogger('DOM', {}); },
380
+ get router() { return isProduction ? noopLogger : createDevLogger('Router', {}); },
381
+ get store() { return isProduction ? noopLogger : createDevLogger('Store', {}); },
382
+ get native() { return isProduction ? noopLogger : createDevLogger('Native', {}); },
383
+ get hmr() { return isProduction ? noopLogger : createDevLogger('HMR', {}); },
384
+ get cli() { return isProduction ? noopLogger : createDevLogger('CLI', {}); }
310
385
  };
311
386
 
312
387
  export default logger;
@@ -1,25 +1,50 @@
1
1
  /**
2
- * Pulse Logger - Production Build (minimal/noop)
3
- * Replace logger.js with this in production builds for smaller bundle.
4
- * @module pulse-js-framework/runtime/logger.prod
2
+ * Pulse Logger - Production Build
3
+ *
4
+ * This module re-exports the main logger with production mode forced.
5
+ * Use this for bundler aliasing or manual import in production builds.
6
+ *
7
+ * @module pulse-js-framework/runtime/logger/prod
8
+ *
9
+ * @example
10
+ * // Vite/Webpack aliasing in config:
11
+ * resolve: {
12
+ * alias: {
13
+ * './logger.js': './logger.prod.js'
14
+ * }
15
+ * }
16
+ *
17
+ * // Or import directly:
18
+ * import { logger } from 'pulse-js-framework/runtime/logger/prod';
5
19
  */
6
20
 
7
- export const LogLevel = { SILENT: 0, ERROR: 1, WARN: 2, INFO: 3, DEBUG: 4 };
21
+ // Import and immediately configure production mode
22
+ import {
23
+ configureLogger,
24
+ LogLevel,
25
+ setLogLevel,
26
+ getLogLevel,
27
+ setFormatter,
28
+ createLogger,
29
+ logger,
30
+ loggers,
31
+ isProductionMode
32
+ } from './logger.js';
8
33
 
9
- const noop = () => {};
10
- const noopLogger = {
11
- error: noop, warn: noop, info: noop, debug: noop,
12
- group: noop, groupEnd: noop, log: noop,
13
- child: () => noopLogger
14
- };
34
+ // Force production mode
35
+ configureLogger({ production: true });
15
36
 
16
- export const setLogLevel = noop;
17
- export const getLogLevel = () => LogLevel.SILENT;
18
- export const setFormatter = noop;
19
- export const createLogger = () => noopLogger;
20
- export const logger = noopLogger;
21
- export const loggers = {
22
- pulse: noopLogger, dom: noopLogger, router: noopLogger,
23
- store: noopLogger, native: noopLogger, hmr: noopLogger, cli: noopLogger
37
+ // Re-export everything
38
+ export {
39
+ LogLevel,
40
+ setLogLevel,
41
+ getLogLevel,
42
+ setFormatter,
43
+ createLogger,
44
+ logger,
45
+ loggers,
46
+ configureLogger,
47
+ isProductionMode
24
48
  };
49
+
25
50
  export default logger;