pulse-js-framework 1.4.4 → 1.4.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/cli/index.js +23 -20
- package/cli/logger.js +122 -0
- package/index.js +8 -2
- package/package.json +32 -5
- package/runtime/dom.js +6 -3
- package/runtime/index.js +2 -0
- package/runtime/logger.js +304 -0
- package/runtime/native.js +7 -4
- package/runtime/pulse.js +308 -25
- package/runtime/store.js +227 -19
- package/types/index.d.ts +15 -0
- package/types/logger.d.ts +122 -0
package/cli/index.js
CHANGED
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { dirname, join, resolve } from 'path';
|
|
9
9
|
import { existsSync, mkdirSync, writeFileSync, readFileSync, cpSync } from 'fs';
|
|
10
|
+
import { log } from './logger.js';
|
|
10
11
|
|
|
11
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
13
|
const __dirname = dirname(__filename);
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
// Version - read dynamically from package.json
|
|
16
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
17
|
+
const VERSION = pkg.version;
|
|
15
18
|
|
|
16
19
|
// Command handlers
|
|
17
20
|
const commands = {
|
|
@@ -38,8 +41,8 @@ async function main() {
|
|
|
38
41
|
if (command in commands) {
|
|
39
42
|
await commands[command](args.slice(1));
|
|
40
43
|
} else {
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
log.error(`Unknown command: ${command}`);
|
|
45
|
+
log.info('Run "pulse help" for usage information.');
|
|
43
46
|
process.exit(1);
|
|
44
47
|
}
|
|
45
48
|
}
|
|
@@ -48,7 +51,7 @@ async function main() {
|
|
|
48
51
|
* Show help message
|
|
49
52
|
*/
|
|
50
53
|
function showHelp() {
|
|
51
|
-
|
|
54
|
+
log.info(`
|
|
52
55
|
Pulse Framework CLI v${VERSION}
|
|
53
56
|
|
|
54
57
|
Usage: pulse <command> [options]
|
|
@@ -102,7 +105,7 @@ Documentation: https://github.com/vincenthirtz/pulse-js-framework
|
|
|
102
105
|
* Show version
|
|
103
106
|
*/
|
|
104
107
|
function showVersion() {
|
|
105
|
-
|
|
108
|
+
log.info(`Pulse Framework v${VERSION}`);
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
/**
|
|
@@ -112,19 +115,19 @@ async function createProject(args) {
|
|
|
112
115
|
const projectName = args[0];
|
|
113
116
|
|
|
114
117
|
if (!projectName) {
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
log.error('Please provide a project name.');
|
|
119
|
+
log.info('Usage: pulse create <project-name>');
|
|
117
120
|
process.exit(1);
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
const projectPath = resolve(process.cwd(), projectName);
|
|
121
124
|
|
|
122
125
|
if (existsSync(projectPath)) {
|
|
123
|
-
|
|
126
|
+
log.error(`Directory "${projectName}" already exists.`);
|
|
124
127
|
process.exit(1);
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
|
|
130
|
+
log.info(`Creating new Pulse project: ${projectName}`);
|
|
128
131
|
|
|
129
132
|
// Create project structure
|
|
130
133
|
mkdirSync(projectPath);
|
|
@@ -281,7 +284,7 @@ dist
|
|
|
281
284
|
|
|
282
285
|
writeFileSync(join(projectPath, '.gitignore'), gitignore);
|
|
283
286
|
|
|
284
|
-
|
|
287
|
+
log.info(`
|
|
285
288
|
Project created successfully!
|
|
286
289
|
|
|
287
290
|
Next steps:
|
|
@@ -297,7 +300,7 @@ Happy coding with Pulse!
|
|
|
297
300
|
* Run development server
|
|
298
301
|
*/
|
|
299
302
|
async function runDev(args) {
|
|
300
|
-
|
|
303
|
+
log.info('Starting Pulse development server...');
|
|
301
304
|
|
|
302
305
|
// Use dynamic import for the dev server module
|
|
303
306
|
const { startDevServer } = await import('./dev.js');
|
|
@@ -308,7 +311,7 @@ async function runDev(args) {
|
|
|
308
311
|
* Build for production
|
|
309
312
|
*/
|
|
310
313
|
async function runBuild(args) {
|
|
311
|
-
|
|
314
|
+
log.info('Building Pulse project for production...');
|
|
312
315
|
|
|
313
316
|
const { buildProject } = await import('./build.js');
|
|
314
317
|
await buildProject(args);
|
|
@@ -318,7 +321,7 @@ async function runBuild(args) {
|
|
|
318
321
|
* Preview production build
|
|
319
322
|
*/
|
|
320
323
|
async function runPreview(args) {
|
|
321
|
-
|
|
324
|
+
log.info('Starting Pulse preview server...');
|
|
322
325
|
|
|
323
326
|
const { previewBuild } = await import('./build.js');
|
|
324
327
|
await previewBuild(args);
|
|
@@ -363,13 +366,13 @@ async function compileFile(args) {
|
|
|
363
366
|
const inputFile = args[0];
|
|
364
367
|
|
|
365
368
|
if (!inputFile) {
|
|
366
|
-
|
|
367
|
-
|
|
369
|
+
log.error('Please provide a file to compile.');
|
|
370
|
+
log.info('Usage: pulse compile <file.pulse>');
|
|
368
371
|
process.exit(1);
|
|
369
372
|
}
|
|
370
373
|
|
|
371
374
|
if (!existsSync(inputFile)) {
|
|
372
|
-
|
|
375
|
+
log.error(`File not found: ${inputFile}`);
|
|
373
376
|
process.exit(1);
|
|
374
377
|
}
|
|
375
378
|
|
|
@@ -381,11 +384,11 @@ async function compileFile(args) {
|
|
|
381
384
|
if (result.success) {
|
|
382
385
|
const outputFile = inputFile.replace(/\.pulse$/, '.js');
|
|
383
386
|
writeFileSync(outputFile, result.code);
|
|
384
|
-
|
|
387
|
+
log.info(`Compiled: ${inputFile} -> ${outputFile}`);
|
|
385
388
|
} else {
|
|
386
|
-
|
|
389
|
+
log.error('Compilation failed:');
|
|
387
390
|
for (const error of result.errors) {
|
|
388
|
-
|
|
391
|
+
log.error(` ${error.message}`);
|
|
389
392
|
}
|
|
390
393
|
process.exit(1);
|
|
391
394
|
}
|
|
@@ -393,6 +396,6 @@ async function compileFile(args) {
|
|
|
393
396
|
|
|
394
397
|
// Run main
|
|
395
398
|
main().catch(error => {
|
|
396
|
-
|
|
399
|
+
log.error('Error:', error.message);
|
|
397
400
|
process.exit(1);
|
|
398
401
|
});
|
package/cli/logger.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse CLI Logger
|
|
3
|
+
* Lightweight logger for CLI tools with support for verbose mode
|
|
4
|
+
* @module pulse-cli/logger
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** @type {boolean} */
|
|
8
|
+
let verboseMode = false;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Enable or disable verbose mode for debug output
|
|
12
|
+
* @param {boolean} enabled - Whether to enable verbose mode
|
|
13
|
+
* @returns {void}
|
|
14
|
+
* @example
|
|
15
|
+
* setVerbose(true);
|
|
16
|
+
* log.debug('This will now be shown');
|
|
17
|
+
*/
|
|
18
|
+
export function setVerbose(enabled) {
|
|
19
|
+
verboseMode = enabled;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Check if verbose mode is currently enabled
|
|
24
|
+
* @returns {boolean} True if verbose mode is enabled
|
|
25
|
+
* @example
|
|
26
|
+
* if (isVerbose()) {
|
|
27
|
+
* // Perform additional logging
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
export function isVerbose() {
|
|
31
|
+
return verboseMode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* CLI Logger object with console-like API
|
|
36
|
+
* @namespace log
|
|
37
|
+
*/
|
|
38
|
+
export const log = {
|
|
39
|
+
/**
|
|
40
|
+
* Log an info message (always shown)
|
|
41
|
+
* @param {...*} args - Values to log
|
|
42
|
+
* @returns {void}
|
|
43
|
+
* @example
|
|
44
|
+
* log.info('Starting server on port', 3000);
|
|
45
|
+
*/
|
|
46
|
+
info(...args) {
|
|
47
|
+
console.log(...args);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log a success message (always shown)
|
|
52
|
+
* @param {...*} args - Values to log
|
|
53
|
+
* @returns {void}
|
|
54
|
+
* @example
|
|
55
|
+
* log.success('Build completed successfully!');
|
|
56
|
+
*/
|
|
57
|
+
success(...args) {
|
|
58
|
+
console.log(...args);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Log a warning message
|
|
63
|
+
* @param {...*} args - Values to log
|
|
64
|
+
* @returns {void}
|
|
65
|
+
* @example
|
|
66
|
+
* log.warn('Deprecated feature used');
|
|
67
|
+
*/
|
|
68
|
+
warn(...args) {
|
|
69
|
+
console.warn(...args);
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Log an error message
|
|
74
|
+
* @param {...*} args - Values to log
|
|
75
|
+
* @returns {void}
|
|
76
|
+
* @example
|
|
77
|
+
* log.error('Failed to compile:', error.message);
|
|
78
|
+
*/
|
|
79
|
+
error(...args) {
|
|
80
|
+
console.error(...args);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Log a debug message (only shown in verbose mode)
|
|
85
|
+
* @param {...*} args - Values to log
|
|
86
|
+
* @returns {void}
|
|
87
|
+
* @example
|
|
88
|
+
* log.debug('Processing file:', filename);
|
|
89
|
+
*/
|
|
90
|
+
debug(...args) {
|
|
91
|
+
if (verboseMode) {
|
|
92
|
+
console.log('[debug]', ...args);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Log a verbose message (only shown in verbose mode)
|
|
98
|
+
* @param {...*} args - Values to log
|
|
99
|
+
* @returns {void}
|
|
100
|
+
* @example
|
|
101
|
+
* log.verbose('Additional details:', data);
|
|
102
|
+
*/
|
|
103
|
+
verbose(...args) {
|
|
104
|
+
if (verboseMode) {
|
|
105
|
+
console.log(...args);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Print a blank line for spacing
|
|
111
|
+
* @returns {void}
|
|
112
|
+
* @example
|
|
113
|
+
* log.info('Section 1');
|
|
114
|
+
* log.newline();
|
|
115
|
+
* log.info('Section 2');
|
|
116
|
+
*/
|
|
117
|
+
newline() {
|
|
118
|
+
console.log();
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export default log;
|
package/index.js
CHANGED
|
@@ -4,14 +4,20 @@
|
|
|
4
4
|
* A declarative DOM framework with CSS selector-based structure
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { readFileSync } from 'fs';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { dirname, join } from 'path';
|
|
10
|
+
|
|
7
11
|
// Runtime exports
|
|
8
12
|
export * from './runtime/index.js';
|
|
9
13
|
|
|
10
14
|
// Compiler exports
|
|
11
15
|
export { compile, parse, tokenize } from './compiler/index.js';
|
|
12
16
|
|
|
13
|
-
// Version
|
|
14
|
-
|
|
17
|
+
// Version - read dynamically from package.json
|
|
18
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf-8'));
|
|
20
|
+
export const VERSION = pkg.version;
|
|
15
21
|
|
|
16
22
|
// Default export
|
|
17
23
|
export default {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pulse-js-framework",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "A declarative DOM framework with CSS selector-based structure and reactive pulsations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
"types": "./types/index.d.ts",
|
|
18
18
|
"default": "./runtime/index.js"
|
|
19
19
|
},
|
|
20
|
+
"./runtime/pulse": {
|
|
21
|
+
"types": "./types/pulse.d.ts",
|
|
22
|
+
"default": "./runtime/pulse.js"
|
|
23
|
+
},
|
|
24
|
+
"./runtime/dom": {
|
|
25
|
+
"types": "./types/dom.d.ts",
|
|
26
|
+
"default": "./runtime/dom.js"
|
|
27
|
+
},
|
|
20
28
|
"./runtime/router": {
|
|
21
29
|
"types": "./types/router.d.ts",
|
|
22
30
|
"default": "./runtime/router.js"
|
|
@@ -25,9 +33,27 @@
|
|
|
25
33
|
"types": "./types/store.d.ts",
|
|
26
34
|
"default": "./runtime/store.js"
|
|
27
35
|
},
|
|
28
|
-
"./runtime
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
"./runtime/native": {
|
|
37
|
+
"types": "./types/index.d.ts",
|
|
38
|
+
"default": "./runtime/native.js"
|
|
39
|
+
},
|
|
40
|
+
"./runtime/logger": {
|
|
41
|
+
"types": "./types/logger.d.ts",
|
|
42
|
+
"default": "./runtime/logger.js"
|
|
43
|
+
},
|
|
44
|
+
"./compiler": {
|
|
45
|
+
"types": "./types/index.d.ts",
|
|
46
|
+
"default": "./compiler/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./compiler/lexer": "./compiler/lexer.js",
|
|
49
|
+
"./compiler/parser": "./compiler/parser.js",
|
|
50
|
+
"./compiler/transformer": "./compiler/transformer.js",
|
|
51
|
+
"./vite": {
|
|
52
|
+
"types": "./types/index.d.ts",
|
|
53
|
+
"default": "./loader/vite-plugin.js"
|
|
54
|
+
},
|
|
55
|
+
"./mobile": "./mobile/bridge/pulse-native.js",
|
|
56
|
+
"./package.json": "./package.json"
|
|
31
57
|
},
|
|
32
58
|
"files": [
|
|
33
59
|
"index.js",
|
|
@@ -50,7 +76,8 @@
|
|
|
50
76
|
"test:lint": "node test/lint.test.js",
|
|
51
77
|
"test:format": "node test/format.test.js",
|
|
52
78
|
"test:analyze": "node test/analyze.test.js",
|
|
53
|
-
"build:netlify": "node scripts/build-netlify.js"
|
|
79
|
+
"build:netlify": "node scripts/build-netlify.js",
|
|
80
|
+
"version": "node scripts/sync-version.js"
|
|
54
81
|
},
|
|
55
82
|
"keywords": [
|
|
56
83
|
"framework",
|
package/runtime/dom.js
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { effect, pulse, batch, onCleanup } from './pulse.js';
|
|
9
|
+
import { loggers } from './logger.js';
|
|
10
|
+
|
|
11
|
+
const log = loggers.dom;
|
|
9
12
|
|
|
10
13
|
// Lifecycle tracking
|
|
11
14
|
let mountCallbacks = [];
|
|
@@ -523,7 +526,7 @@ export function component(setup) {
|
|
|
523
526
|
try {
|
|
524
527
|
cb();
|
|
525
528
|
} catch (e) {
|
|
526
|
-
|
|
529
|
+
log.error('Mount callback error:', e);
|
|
527
530
|
}
|
|
528
531
|
}
|
|
529
532
|
});
|
|
@@ -559,7 +562,7 @@ export function portal(children, target) {
|
|
|
559
562
|
: target;
|
|
560
563
|
|
|
561
564
|
if (!resolvedTarget) {
|
|
562
|
-
|
|
565
|
+
log.warn('Portal target not found:', target);
|
|
563
566
|
return document.createComment('portal-target-not-found');
|
|
564
567
|
}
|
|
565
568
|
|
|
@@ -653,7 +656,7 @@ export function errorBoundary(children, fallback) {
|
|
|
653
656
|
marker.parentNode?.insertBefore(fragment, marker.nextSibling);
|
|
654
657
|
}
|
|
655
658
|
} catch (e) {
|
|
656
|
-
|
|
659
|
+
log.error('Error in component:', e);
|
|
657
660
|
error.set(e);
|
|
658
661
|
// Re-render with error
|
|
659
662
|
if (!hasError) {
|
package/runtime/index.js
CHANGED
|
@@ -7,9 +7,11 @@ export * from './dom.js';
|
|
|
7
7
|
export * from './router.js';
|
|
8
8
|
export * from './store.js';
|
|
9
9
|
export * from './native.js';
|
|
10
|
+
export * from './logger.js';
|
|
10
11
|
|
|
11
12
|
export { default as PulseCore } from './pulse.js';
|
|
12
13
|
export { default as PulseDOM } from './dom.js';
|
|
13
14
|
export { default as PulseRouter } from './router.js';
|
|
14
15
|
export { default as PulseStore } from './store.js';
|
|
15
16
|
export { default as PulseNative } from './native.js';
|
|
17
|
+
export { default as PulseLogger } from './logger.js';
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Logger - Centralized logging with namespaces and levels
|
|
3
|
+
* @module pulse-js-framework/runtime/logger
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* import { logger, createLogger } from './logger.js';
|
|
7
|
+
*
|
|
8
|
+
* // Default logger
|
|
9
|
+
* logger.info('Hello');
|
|
10
|
+
* logger.warn('Warning');
|
|
11
|
+
* logger.error('Error');
|
|
12
|
+
*
|
|
13
|
+
* // Namespaced logger
|
|
14
|
+
* const log = createLogger('Router');
|
|
15
|
+
* log.info('Navigating to /home'); // [Router] Navigating to /home
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Log level constants
|
|
20
|
+
* @readonly
|
|
21
|
+
* @enum {number}
|
|
22
|
+
*/
|
|
23
|
+
export const LogLevel = {
|
|
24
|
+
/** No logging */
|
|
25
|
+
SILENT: 0,
|
|
26
|
+
/** Only errors */
|
|
27
|
+
ERROR: 1,
|
|
28
|
+
/** Errors and warnings */
|
|
29
|
+
WARN: 2,
|
|
30
|
+
/** Errors, warnings, and info (default) */
|
|
31
|
+
INFO: 3,
|
|
32
|
+
/** All messages including debug */
|
|
33
|
+
DEBUG: 4
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** @type {number} */
|
|
37
|
+
let globalLevel = LogLevel.INFO;
|
|
38
|
+
|
|
39
|
+
/** @type {LogFormatter|null} */
|
|
40
|
+
let globalFormatter = null;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @callback LogFormatter
|
|
44
|
+
* @param {'error'|'warn'|'info'|'debug'} level - The log level
|
|
45
|
+
* @param {string|null} namespace - The logger namespace
|
|
46
|
+
* @param {Array<*>} args - The arguments to log
|
|
47
|
+
* @returns {string} The formatted log message
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Set the global log level for all loggers
|
|
52
|
+
* @param {number} level - A LogLevel value (SILENT=0, ERROR=1, WARN=2, INFO=3, DEBUG=4)
|
|
53
|
+
* @returns {void}
|
|
54
|
+
* @example
|
|
55
|
+
* setLogLevel(LogLevel.DEBUG); // Enable all logging
|
|
56
|
+
* setLogLevel(LogLevel.SILENT); // Disable all logging
|
|
57
|
+
*/
|
|
58
|
+
export function setLogLevel(level) {
|
|
59
|
+
globalLevel = level;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get the current global log level
|
|
64
|
+
* @returns {number} The current LogLevel value
|
|
65
|
+
* @example
|
|
66
|
+
* const level = getLogLevel();
|
|
67
|
+
* if (level >= LogLevel.DEBUG) {
|
|
68
|
+
* // Debug logging is enabled
|
|
69
|
+
* }
|
|
70
|
+
*/
|
|
71
|
+
export function getLogLevel() {
|
|
72
|
+
return globalLevel;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Set a custom formatter function for all loggers
|
|
77
|
+
* @param {LogFormatter|null} formatter - Custom formatter function, or null to use default
|
|
78
|
+
* @returns {void}
|
|
79
|
+
* @example
|
|
80
|
+
* setFormatter((level, namespace, args) => {
|
|
81
|
+
* const timestamp = new Date().toISOString();
|
|
82
|
+
* const prefix = namespace ? `[${namespace}]` : '';
|
|
83
|
+
* return `${timestamp} ${level.toUpperCase()} ${prefix} ${args.join(' ')}`;
|
|
84
|
+
* });
|
|
85
|
+
*/
|
|
86
|
+
export function setFormatter(formatter) {
|
|
87
|
+
globalFormatter = formatter;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Format message arguments with optional namespace prefix
|
|
92
|
+
* @private
|
|
93
|
+
* @param {string|null} namespace - The logger namespace
|
|
94
|
+
* @param {Array<*>} args - Arguments to format
|
|
95
|
+
* @returns {Array<*>} Formatted arguments array
|
|
96
|
+
*/
|
|
97
|
+
function formatArgs(namespace, args) {
|
|
98
|
+
if (!namespace) return args;
|
|
99
|
+
|
|
100
|
+
// If first arg is a string, prepend namespace
|
|
101
|
+
if (typeof args[0] === 'string') {
|
|
102
|
+
return [`[${namespace}] ${args[0]}`, ...args.slice(1)];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Otherwise, add namespace as first arg
|
|
106
|
+
return [`[${namespace}]`, ...args];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @typedef {Object} Logger
|
|
111
|
+
* @property {function(...*): void} error - Log error message
|
|
112
|
+
* @property {function(...*): void} warn - Log warning message
|
|
113
|
+
* @property {function(...*): void} info - Log info message
|
|
114
|
+
* @property {function(...*): void} debug - Log debug message
|
|
115
|
+
* @property {function(string): void} group - Start a collapsed log group
|
|
116
|
+
* @property {function(): void} groupEnd - End the current log group
|
|
117
|
+
* @property {function(number, ...*): void} log - Log with custom level
|
|
118
|
+
* @property {function(string): Logger} child - Create a child logger with sub-namespace
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @typedef {Object} LoggerOptions
|
|
123
|
+
* @property {number} [level] - Override global level for this logger instance
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Create a logger instance with optional namespace
|
|
128
|
+
* @param {string|null} [namespace=null] - Logger namespace (e.g., 'Router', 'Store')
|
|
129
|
+
* @param {LoggerOptions} [options={}] - Logger configuration options
|
|
130
|
+
* @returns {Logger} A logger instance with error, warn, info, debug methods
|
|
131
|
+
* @example
|
|
132
|
+
* const log = createLogger('MyComponent');
|
|
133
|
+
* log.info('Initialized'); // [MyComponent] Initialized
|
|
134
|
+
* log.error('Failed', { code: 500 }); // [MyComponent] Failed { code: 500 }
|
|
135
|
+
*
|
|
136
|
+
* // With custom level
|
|
137
|
+
* const debugLog = createLogger('Debug', { level: LogLevel.DEBUG });
|
|
138
|
+
*/
|
|
139
|
+
export function createLogger(namespace = null, options = {}) {
|
|
140
|
+
const localLevel = options.level;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if a message at the given level should be logged
|
|
144
|
+
* @param {number} level - The log level to check
|
|
145
|
+
* @returns {boolean} True if the message should be logged
|
|
146
|
+
*/
|
|
147
|
+
function shouldLog(level) {
|
|
148
|
+
const effectiveLevel = localLevel !== undefined ? localLevel : globalLevel;
|
|
149
|
+
return level <= effectiveLevel;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
/**
|
|
154
|
+
* Log an error message (shown unless level is SILENT)
|
|
155
|
+
* @param {...*} args - Values to log
|
|
156
|
+
* @returns {void}
|
|
157
|
+
*/
|
|
158
|
+
error(...args) {
|
|
159
|
+
if (shouldLog(LogLevel.ERROR)) {
|
|
160
|
+
if (globalFormatter) {
|
|
161
|
+
console.error(globalFormatter('error', namespace, args));
|
|
162
|
+
} else {
|
|
163
|
+
console.error(...formatArgs(namespace, args));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Log a warning message (shown at WARN level and above)
|
|
170
|
+
* @param {...*} args - Values to log
|
|
171
|
+
* @returns {void}
|
|
172
|
+
*/
|
|
173
|
+
warn(...args) {
|
|
174
|
+
if (shouldLog(LogLevel.WARN)) {
|
|
175
|
+
if (globalFormatter) {
|
|
176
|
+
console.warn(globalFormatter('warn', namespace, args));
|
|
177
|
+
} else {
|
|
178
|
+
console.warn(...formatArgs(namespace, args));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Log an info message (shown at INFO level and above)
|
|
185
|
+
* @param {...*} args - Values to log
|
|
186
|
+
* @returns {void}
|
|
187
|
+
*/
|
|
188
|
+
info(...args) {
|
|
189
|
+
if (shouldLog(LogLevel.INFO)) {
|
|
190
|
+
if (globalFormatter) {
|
|
191
|
+
console.log(globalFormatter('info', namespace, args));
|
|
192
|
+
} else {
|
|
193
|
+
console.log(...formatArgs(namespace, args));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Log a debug message (only shown at DEBUG level)
|
|
200
|
+
* @param {...*} args - Values to log
|
|
201
|
+
* @returns {void}
|
|
202
|
+
*/
|
|
203
|
+
debug(...args) {
|
|
204
|
+
if (shouldLog(LogLevel.DEBUG)) {
|
|
205
|
+
if (globalFormatter) {
|
|
206
|
+
console.log(globalFormatter('debug', namespace, args));
|
|
207
|
+
} else {
|
|
208
|
+
console.log(...formatArgs(namespace, args));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Start a collapsed log group (only shown at DEBUG level)
|
|
215
|
+
* @param {string} label - The group label
|
|
216
|
+
* @returns {void}
|
|
217
|
+
*/
|
|
218
|
+
group(label) {
|
|
219
|
+
if (shouldLog(LogLevel.DEBUG)) {
|
|
220
|
+
console.group(namespace ? `[${namespace}] ${label}` : label);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* End the current log group
|
|
226
|
+
* @returns {void}
|
|
227
|
+
*/
|
|
228
|
+
groupEnd() {
|
|
229
|
+
if (shouldLog(LogLevel.DEBUG)) {
|
|
230
|
+
console.groupEnd();
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Log a message at a custom level
|
|
236
|
+
* @param {number} level - The LogLevel to use
|
|
237
|
+
* @param {...*} args - Values to log
|
|
238
|
+
* @returns {void}
|
|
239
|
+
*/
|
|
240
|
+
log(level, ...args) {
|
|
241
|
+
if (shouldLog(level)) {
|
|
242
|
+
const formatted = formatArgs(namespace, args);
|
|
243
|
+
switch (level) {
|
|
244
|
+
case LogLevel.ERROR:
|
|
245
|
+
console.error(...formatted);
|
|
246
|
+
break;
|
|
247
|
+
case LogLevel.WARN:
|
|
248
|
+
console.warn(...formatted);
|
|
249
|
+
break;
|
|
250
|
+
default:
|
|
251
|
+
console.log(...formatted);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Create a child logger with an additional namespace segment
|
|
258
|
+
* @param {string} childNamespace - The child namespace to append
|
|
259
|
+
* @returns {Logger} A new logger with combined namespace
|
|
260
|
+
* @example
|
|
261
|
+
* const log = createLogger('App');
|
|
262
|
+
* const routerLog = log.child('Router');
|
|
263
|
+
* routerLog.info('Navigate'); // [App:Router] Navigate
|
|
264
|
+
*/
|
|
265
|
+
child(childNamespace) {
|
|
266
|
+
const combined = namespace
|
|
267
|
+
? `${namespace}:${childNamespace}`
|
|
268
|
+
: childNamespace;
|
|
269
|
+
return createLogger(combined, options);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Default logger instance without namespace
|
|
276
|
+
* @type {Logger}
|
|
277
|
+
* @example
|
|
278
|
+
* import { logger } from './logger.js';
|
|
279
|
+
* logger.info('Application started');
|
|
280
|
+
*/
|
|
281
|
+
export const logger = createLogger();
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Pre-configured loggers for common Pulse subsystems
|
|
285
|
+
* @type {Object.<string, Logger>}
|
|
286
|
+
* @property {Logger} pulse - Logger for core reactivity system
|
|
287
|
+
* @property {Logger} dom - Logger for DOM operations
|
|
288
|
+
* @property {Logger} router - Logger for routing
|
|
289
|
+
* @property {Logger} store - Logger for state management
|
|
290
|
+
* @property {Logger} native - Logger for native/mobile features
|
|
291
|
+
* @property {Logger} hmr - Logger for hot module replacement
|
|
292
|
+
* @property {Logger} cli - Logger for CLI tools
|
|
293
|
+
*/
|
|
294
|
+
export const loggers = {
|
|
295
|
+
pulse: createLogger('Pulse'),
|
|
296
|
+
dom: createLogger('DOM'),
|
|
297
|
+
router: createLogger('Router'),
|
|
298
|
+
store: createLogger('Store'),
|
|
299
|
+
native: createLogger('Native'),
|
|
300
|
+
hmr: createLogger('HMR'),
|
|
301
|
+
cli: createLogger('CLI')
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export default logger;
|