logger-chroma 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.
- package/.github/workflows/npmpublish.yml +48 -0
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/index.cjs +19 -0
- package/index.d.ts +89 -0
- package/index.js +85 -0
- package/package.json +50 -0
- package/terminal.png +0 -0
- package/test/index.test.js +115 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# This workflow will run tests using node and then publish a package to npm using Trusted Publishing (OIDC)
|
|
2
|
+
# For more information see: https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow
|
|
3
|
+
|
|
4
|
+
name: logger-chroma NPM Package
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ main ]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [ main ]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
|
|
16
|
+
# Skip Dependabot PRs for CI/CD
|
|
17
|
+
if: ${{ github.actor != 'dependabot[bot]' }}
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: lts/krypton
|
|
24
|
+
|
|
25
|
+
- run: npm install
|
|
26
|
+
- run: npm test
|
|
27
|
+
|
|
28
|
+
publish-npm:
|
|
29
|
+
needs: build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
|
|
32
|
+
# Skip Dependabot PRs
|
|
33
|
+
if: ${{ github.actor != 'dependabot[bot]' }}
|
|
34
|
+
|
|
35
|
+
# Required for OIDC Trusted Publishing
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
id-token: write # 👈 REQUIRED for Trusted Publishing
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- uses: actions/setup-node@v4
|
|
43
|
+
with:
|
|
44
|
+
node-version: lts/krypton
|
|
45
|
+
registry-url: https://registry.npmjs.org/
|
|
46
|
+
|
|
47
|
+
- run: npm install
|
|
48
|
+
- run: npm publish
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# logger-chroma
|
|
2
|
+
|
|
3
|
+
<p align="center"><a href="https://nodei.co/npm/logger-chroma/"><img src="https://nodei.co/npm/logger-chroma.png"></a></a></p>
|
|
4
|
+
<p align="center">
|
|
5
|
+
<img src="https://img.shields.io/badge/License-MIT-yellow.svg">
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<img src="terminal.png" alt="Terminal output image">
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
* 🎨 A lightweight, high-performance Node.js logging utility designed for developers who need to visualize complex, nested operations. `logger-chroma` transforms flat, messy console outputs into a beautiful, structured tree that makes debugging logical flows intuitive.
|
|
13
|
+
* 👨💻 Optimized for modern terminals like `Windows Terminal`, `VS Code Integrated Terminal`, and `iTerm2`, `Windows Git Bash Terminal` where box-drawing characters are rendered natively.
|
|
14
|
+
* ♻️ Works seamlessly with `CommonJS`, `ESM` and `TypeScript`
|
|
15
|
+
|
|
16
|
+
# 📦 Install via [NPM](https://www.npmjs.com/package/logger-chroma)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ npm i logger-chroma
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
# 💻 Usage
|
|
23
|
+
|
|
24
|
+
- See examples below
|
|
25
|
+
|
|
26
|
+
## CommonJS
|
|
27
|
+
```javascript
|
|
28
|
+
const loggerChroma = require('logger-chroma');
|
|
29
|
+
|
|
30
|
+
// --| Same code as below in ESM and TypeScript
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## ESM or TypeScript
|
|
34
|
+
```javascript
|
|
35
|
+
import loggerChroma from 'logger-chroma';
|
|
36
|
+
|
|
37
|
+
// --| Server start
|
|
38
|
+
loggerChroma.info("Server starting on port", 3000, "🚀");
|
|
39
|
+
|
|
40
|
+
// --| Environment info
|
|
41
|
+
loggerChroma.debug({ env: process.env.NODE_ENV || "development", version: "1.0.0" }, "💡", "Current environment");
|
|
42
|
+
|
|
43
|
+
// --| Full HTTP request handling example
|
|
44
|
+
loggerChroma.group("HTTP GET /users", () => {
|
|
45
|
+
loggerChroma.info("Request received", "📥");
|
|
46
|
+
|
|
47
|
+
// --| Authentication
|
|
48
|
+
loggerChroma.group("Auth check", () => {
|
|
49
|
+
const user = { id: 1, role: "admin", permissions: ["read", "write"] };
|
|
50
|
+
loggerChroma.debug(user, "🕵️", "User payload");
|
|
51
|
+
|
|
52
|
+
loggerChroma.group("Token validation", () => {
|
|
53
|
+
const token = { valid: true, expires: "2026-03-05T18:00:00Z" };
|
|
54
|
+
loggerChroma.debug(token, "🔑", "Token info");
|
|
55
|
+
loggerChroma.info("Token is valid", "✅");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
loggerChroma.info("Authentication passed", "✅");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// --| Database query
|
|
62
|
+
loggerChroma.group("DB query", () => {
|
|
63
|
+
const users = [
|
|
64
|
+
{ id: 1, name: "Alice", active: true },
|
|
65
|
+
{ id: 2, name: "Bob", active: false },
|
|
66
|
+
{ id: 3, name: "Charlie", active: true },
|
|
67
|
+
];
|
|
68
|
+
loggerChroma.debug(users, "🗄️", "Fetched users");
|
|
69
|
+
|
|
70
|
+
loggerChroma.group("Filter active users", () => {
|
|
71
|
+
const activeUsers = users.filter(u => u.active);
|
|
72
|
+
loggerChroma.info(activeUsers, "🌟", "Active users list");
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
loggerChroma.info("Request completed", "🎯");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// --| Another route example
|
|
80
|
+
loggerChroma.group("HTTP POST /orders", () => {
|
|
81
|
+
loggerChroma.info("Request received", "📥");
|
|
82
|
+
|
|
83
|
+
loggerChroma.group("Auth check", () => {
|
|
84
|
+
const user = { id: 2, role: "customer" };
|
|
85
|
+
loggerChroma.debug(user, "🕵️", "User payload");
|
|
86
|
+
loggerChroma.info("Authentication passed", "✅");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
loggerChroma.group("DB insert order", () => {
|
|
90
|
+
const order = { id: 101, items: ["apple", "banana"], total: 12.5 };
|
|
91
|
+
loggerChroma.debug(order, "🛒", "Order object");
|
|
92
|
+
|
|
93
|
+
loggerChroma.group("Send notification", () => {
|
|
94
|
+
const notification = { to: "user@example.com", status: "sent" };
|
|
95
|
+
loggerChroma.info(notification, "📧", "Notification sent");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
loggerChroma.info("Order processed successfully", "🎯");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// --| Error example
|
|
103
|
+
try {
|
|
104
|
+
throw new Error("Something went horribly wrong!");
|
|
105
|
+
} catch (err) {
|
|
106
|
+
loggerChroma.error(err, "🦄", "Critical error during request handling");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// --| Final server ready message
|
|
110
|
+
loggerChroma.info("Server ready to accept requests", "✨");
|
|
111
|
+
```
|
package/index.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* logger-chroma - 🦄 A colorful, developer-friendly Node.js logger with timestamps, emojis, pretty-printed objects, and grouped logs for clear, readable output.
|
|
3
|
+
* @version: v1.0.0
|
|
4
|
+
* @link: https://github.com/tutyamxx/logger-chroma
|
|
5
|
+
* @license: MIT
|
|
6
|
+
**/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// --| CommonJS wrapper for loggerChroma
|
|
10
|
+
const esmLogger = require('./index.js');
|
|
11
|
+
|
|
12
|
+
// --| Export default for require('logger-chroma')
|
|
13
|
+
const loggerChroma = esmLogger.default ?? esmLogger;
|
|
14
|
+
|
|
15
|
+
module.exports = loggerChroma;
|
|
16
|
+
|
|
17
|
+
// --| Named and default properties for better interop
|
|
18
|
+
module.exports.loggerChroma = loggerChroma;
|
|
19
|
+
module.exports.default = loggerChroma;
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for LoggerChroma.
|
|
3
|
+
*/
|
|
4
|
+
export interface LoggerConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Show timestamps in the log output.
|
|
7
|
+
* @default true
|
|
8
|
+
* Note: timestamps are always enabled in the current version.
|
|
9
|
+
*/
|
|
10
|
+
timestampEnabled?: boolean;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Number of spaces used for indenting grouped logs.
|
|
14
|
+
* @default 2
|
|
15
|
+
*/
|
|
16
|
+
groupIndentSize?: number;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Custom color and label configuration per log level.
|
|
20
|
+
* Key is the log level name (`info`, `warn`, `error`, `debug`, etc.).
|
|
21
|
+
*/
|
|
22
|
+
levelColors?: Record<string, LevelConfig>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Configuration for a single log level.
|
|
27
|
+
*/
|
|
28
|
+
export interface LevelConfig {
|
|
29
|
+
/**
|
|
30
|
+
* Function to colorize the log text. Defaults to identity function.
|
|
31
|
+
*/
|
|
32
|
+
color?: (text: string) => string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Label displayed in square brackets in the log prefix.
|
|
36
|
+
*/
|
|
37
|
+
label: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Type definition for a single logging function.
|
|
42
|
+
*
|
|
43
|
+
* Accepts any number of arguments of any type: strings, numbers, objects, arrays, or emojis.
|
|
44
|
+
*/
|
|
45
|
+
export type LogFunction = (...args: any[]) => void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The LoggerChroma interface.
|
|
49
|
+
*/
|
|
50
|
+
export interface LoggerChroma {
|
|
51
|
+
/**
|
|
52
|
+
* Logs an info-level message.
|
|
53
|
+
*/
|
|
54
|
+
info: LogFunction;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Logs a warning-level message.
|
|
58
|
+
*/
|
|
59
|
+
warn: LogFunction;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Logs an error-level message.
|
|
63
|
+
*/
|
|
64
|
+
error: LogFunction;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Logs a debug-level message.
|
|
68
|
+
*/
|
|
69
|
+
debug: LogFunction;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a grouped log section.
|
|
73
|
+
*
|
|
74
|
+
* Inner log lines are automatically prefixed with `| ` and indented according to `config.groupIndentSize`.
|
|
75
|
+
* Nested groups are fully supported; each level increases indentation.
|
|
76
|
+
*
|
|
77
|
+
* @param title - The title of the log group.
|
|
78
|
+
* @param callback - Function that contains logs to be grouped.
|
|
79
|
+
*/
|
|
80
|
+
group: (title: string, callback?: () => void) => void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Current logger configuration.
|
|
84
|
+
*/
|
|
85
|
+
config: LoggerConfig;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
declare const loggerChroma: LoggerChroma;
|
|
89
|
+
export default loggerChroma;
|
package/index.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* logger-chroma - 🦄 A colorful, developer-friendly Node.js logger with timestamps, emojis, pretty-printed objects, and grouped logs for clear, readable output.
|
|
3
|
+
* @version: v1.0.0
|
|
4
|
+
* @link: https://github.com/tutyamxx/logger-chroma
|
|
5
|
+
* @license: MIT
|
|
6
|
+
**/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import util from 'util';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
|
|
12
|
+
const logLevels = {
|
|
13
|
+
info: { color: chalk.green, label: 'INFO ' },
|
|
14
|
+
warn: { color: chalk.yellow, label: 'WARN ' },
|
|
15
|
+
error: { color: chalk.red, label: 'ERROR' },
|
|
16
|
+
debug: { color: chalk.blue, label: 'DEBUG' },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const defaultLoggerConfig = {
|
|
20
|
+
timestampEnabled: true,
|
|
21
|
+
groupIndentSize: 2,
|
|
22
|
+
levelColors: logLevels,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getFormattedTimestamp = () => new Date().toISOString().replace('T', ' ').split('.')[0];
|
|
26
|
+
const prettyPrintObject = (obj) => util.inspect(obj, { colors: true, depth: null });
|
|
27
|
+
|
|
28
|
+
const generateLogPrefix = (level, customEmoji, config, depth) => {
|
|
29
|
+
const levelConfig = config.levelColors?.[level] ?? { color: (text) => text, label: level.toUpperCase() };
|
|
30
|
+
const timestampPart = config.timestampEnabled ? `[${getFormattedTimestamp()}] ` : '';
|
|
31
|
+
|
|
32
|
+
let indent = '';
|
|
33
|
+
for (let i = 0; i < depth; i++) {
|
|
34
|
+
indent += '│ ';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const emojiPart = customEmoji ? `${customEmoji} ` : ' ';
|
|
38
|
+
|
|
39
|
+
return `${timestampPart}${indent}${emojiPart}${levelConfig.color(`[${levelConfig.label}]`)}`;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const createLoggerFunction = (level) => (message, customEmoji, ...additionalArgs) => {
|
|
43
|
+
const config = createLoggerFunction.config ?? defaultLoggerConfig;
|
|
44
|
+
const depth = createLoggerFunction.currentDepth ?? 0;
|
|
45
|
+
const prefix = generateLogPrefix(level, customEmoji, config, depth);
|
|
46
|
+
|
|
47
|
+
const formattedMessage = [message, ...additionalArgs]
|
|
48
|
+
?.map(arg => typeof arg === 'object' ? prettyPrintObject(arg) : arg)
|
|
49
|
+
?.join(' ')
|
|
50
|
+
?.split('\n')
|
|
51
|
+
?.map(line => `${prefix} ${line}`)
|
|
52
|
+
?.join('\n');
|
|
53
|
+
|
|
54
|
+
console.log(formattedMessage);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const createLogGroup = (groupTitle, groupCallback) => {
|
|
58
|
+
const config = createLoggerFunction.config ?? defaultLoggerConfig;
|
|
59
|
+
const depth = createLoggerFunction.currentDepth ?? 0;
|
|
60
|
+
const timestamp = config.timestampEnabled ? `[${getFormattedTimestamp()}] ` : '';
|
|
61
|
+
|
|
62
|
+
let parentPipes = '';
|
|
63
|
+
for (let i = 0; i < depth; i++) {
|
|
64
|
+
parentPipes += '│ ';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(`${timestamp}${parentPipes}┌─ ${groupTitle}`);
|
|
68
|
+
|
|
69
|
+
createLoggerFunction.currentDepth = depth + 1;
|
|
70
|
+
|
|
71
|
+
if (typeof groupCallback === 'function') {
|
|
72
|
+
groupCallback();
|
|
73
|
+
}
|
|
74
|
+
createLoggerFunction.currentDepth = depth;
|
|
75
|
+
|
|
76
|
+
console.log(`${timestamp}${parentPipes}└─ End ${groupTitle}`);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const loggerChroma = {};
|
|
80
|
+
Object.keys(logLevels).forEach(level => loggerChroma[level] = createLoggerFunction(level));
|
|
81
|
+
|
|
82
|
+
loggerChroma.group = createLogGroup;
|
|
83
|
+
loggerChroma.config = defaultLoggerConfig;
|
|
84
|
+
|
|
85
|
+
export default loggerChroma;
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "logger-chroma",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "🦄 A colorful, developer-friendly Node.js logger with timestamps, emojis, pretty-printed objects, and grouped logs for clear, readable output.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./index.js",
|
|
10
|
+
"require": "./index.cjs",
|
|
11
|
+
"types": "./index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/tutyamxx/logger-chroma.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"logger",
|
|
23
|
+
"logging",
|
|
24
|
+
"colorful",
|
|
25
|
+
"pretty",
|
|
26
|
+
"emoji",
|
|
27
|
+
"nodejs",
|
|
28
|
+
"debug",
|
|
29
|
+
"grouped-logs",
|
|
30
|
+
"structured-logs",
|
|
31
|
+
"console",
|
|
32
|
+
"dev-tools",
|
|
33
|
+
"readable-logs",
|
|
34
|
+
"cli",
|
|
35
|
+
"developer-friendly",
|
|
36
|
+
"timed-logs"
|
|
37
|
+
],
|
|
38
|
+
"author": "tuty",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/tutyamxx/logger-chroma/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/tutyamxx/logger-chroma#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"chalk": "^5.6.2"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"jest": "^30.2.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/terminal.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import loggerChroma from '../index.js';
|
|
2
|
+
import { jest } from '@jest/globals';
|
|
3
|
+
|
|
4
|
+
const stripAnsi = (str) => str.replace(/\u001b\[[0-9;]*m/g, '');
|
|
5
|
+
|
|
6
|
+
describe('Logger Chroma Unit Tests', () => {
|
|
7
|
+
let logSpy;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
logSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
11
|
+
|
|
12
|
+
const infoFn = loggerChroma.info;
|
|
13
|
+
if (infoFn) {
|
|
14
|
+
Object.getPrototypeOf(infoFn).constructor.currentDepth = 0;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => logSpy.mockRestore());
|
|
19
|
+
|
|
20
|
+
describe('Basic Logging', () => {
|
|
21
|
+
test('Should log a simple info message with the correct label', () => {
|
|
22
|
+
loggerChroma.info('Hello World');
|
|
23
|
+
const output = stripAnsi(logSpy.mock.calls[0][0]);
|
|
24
|
+
|
|
25
|
+
expect(output).toContain('[INFO ]');
|
|
26
|
+
expect(output).toContain('Hello World');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('Should include custom emojis and maintain alignment', () => {
|
|
30
|
+
loggerChroma.info('Message A', '🚀');
|
|
31
|
+
loggerChroma.info('Message B', '🔥');
|
|
32
|
+
|
|
33
|
+
const outA = stripAnsi(logSpy.mock.calls[0][0]);
|
|
34
|
+
const outB = stripAnsi(logSpy.mock.calls[1][0]);
|
|
35
|
+
|
|
36
|
+
expect(outA.indexOf('[INFO ]')).toBe(outB.indexOf('[INFO ]'));
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('Grouping & Hierarchy', () => {
|
|
41
|
+
test('Should render group brackets and nested pipes correctly', () => {
|
|
42
|
+
loggerChroma.group('My Group', () => {
|
|
43
|
+
loggerChroma.info('Inside Log');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const header = stripAnsi(logSpy.mock.calls[0][0]);
|
|
47
|
+
const body = stripAnsi(logSpy.mock.calls[1][0]);
|
|
48
|
+
const footer = stripAnsi(logSpy.mock.calls[2][0]);
|
|
49
|
+
|
|
50
|
+
expect(header).toContain('┌─ My Group');
|
|
51
|
+
expect(body).toContain('│');
|
|
52
|
+
expect(body).toContain('Inside Log');
|
|
53
|
+
expect(footer).toContain('└─ End My Group');
|
|
54
|
+
|
|
55
|
+
expect(header.indexOf('┌')).toBe(body.indexOf('│'));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('Should support deep nesting with multiple pipes', () => {
|
|
59
|
+
loggerChroma.group('L1', () => {
|
|
60
|
+
loggerChroma.group('L2', () => {
|
|
61
|
+
loggerChroma.info('Deep');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const deepLog = stripAnsi(logSpy.mock.calls[2][0]);
|
|
66
|
+
const pipeCount = (deepLog.match(/│/g) || []).length;
|
|
67
|
+
|
|
68
|
+
expect(pipeCount).toBe(2);
|
|
69
|
+
expect(deepLog).toContain('Deep');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('Data Formatting', () => {
|
|
74
|
+
test('Should pretty print objects using util.inspect', () => {
|
|
75
|
+
const data = { id: 123, status: 'ok' };
|
|
76
|
+
loggerChroma.info('Data:', null, data);
|
|
77
|
+
|
|
78
|
+
const output = stripAnsi(logSpy.mock.calls[0][0]);
|
|
79
|
+
expect(output).toContain('id: 123');
|
|
80
|
+
expect(output).toContain("status: 'ok'");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('Should handle multi-line strings by adding pipes to every line', () => {
|
|
84
|
+
loggerChroma.group('MultiLine', () => {
|
|
85
|
+
loggerChroma.info('Line 1\nLine 2');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const output = stripAnsi(logSpy.mock.calls[1][0]);
|
|
89
|
+
const lines = output.split('\n');
|
|
90
|
+
|
|
91
|
+
expect(lines[0]).toContain('│');
|
|
92
|
+
expect(lines[0]).toContain('Line 1');
|
|
93
|
+
expect(lines[1]).toContain('│');
|
|
94
|
+
expect(lines[1]).toContain('Line 2');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('Edge Cases', () => {
|
|
99
|
+
test('Should not throw if groupCallback is not a function', () => {
|
|
100
|
+
expect(() => loggerChroma.group('Empty Group', null)).not.toThrow();
|
|
101
|
+
expect(logSpy).toHaveBeenCalledTimes(2);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('Should respect timestampEnabled being disabled', () => {
|
|
105
|
+
const original = loggerChroma.config.timestampEnabled;
|
|
106
|
+
loggerChroma.config.timestampEnabled = false;
|
|
107
|
+
|
|
108
|
+
loggerChroma.info('No timestamp');
|
|
109
|
+
const output = stripAnsi(logSpy.mock.calls[0][0]);
|
|
110
|
+
|
|
111
|
+
expect(output).not.toMatch(/^\[\d{4}-\d{2}-\d{2}/);
|
|
112
|
+
loggerChroma.config.timestampEnabled = original;
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|