@ix-xs/node-comfort 1.1.31 → 2.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/CHANGELOG.md +190 -0
- package/LICENSE +21 -0
- package/README.md +210 -748
- package/index.js +84 -13
- package/package.json +201 -21
- package/src/Arr.js +901 -0
- package/src/Async.js +585 -0
- package/src/Cache.js +329 -0
- package/src/Checker.js +979 -188
- package/src/Cli.js +1034 -0
- package/src/Color.js +415 -0
- package/src/Crypto.js +707 -0
- package/src/Emitter.js +289 -0
- package/src/Env.js +555 -0
- package/src/FS.js +1483 -768
- package/src/Func.js +692 -0
- package/src/Http.js +538 -0
- package/src/Id.js +418 -0
- package/src/Logger.js +739 -307
- package/src/Num.js +849 -0
- package/src/Obj.js +904 -0
- package/src/SQLite.js +1308 -994
- package/src/Schema.js +1586 -0
- package/src/Str.js +999 -0
- package/src/Sys.js +511 -0
- package/src/Time.js +1323 -0
- package/src/Utils.js +321 -325
- package/src/errors.js +292 -0
- package/types/index.d.ts +693 -120
- package/types/src/Arr.d.ts +562 -0
- package/types/src/Arr.d.ts.map +1 -0
- package/types/src/Async.d.ts +321 -0
- package/types/src/Async.d.ts.map +1 -0
- package/types/src/Cache.d.ts +195 -0
- package/types/src/Cache.d.ts.map +1 -0
- package/types/src/Checker.d.ts +609 -81
- package/types/src/Checker.d.ts.map +1 -1
- package/types/src/Cli.d.ts +582 -0
- package/types/src/Cli.d.ts.map +1 -0
- package/types/src/Color.d.ts +294 -0
- package/types/src/Color.d.ts.map +1 -0
- package/types/src/Crypto.d.ts +534 -0
- package/types/src/Crypto.d.ts.map +1 -0
- package/types/src/Emitter.d.ts +170 -0
- package/types/src/Emitter.d.ts.map +1 -0
- package/types/src/Env.d.ts +382 -0
- package/types/src/Env.d.ts.map +1 -0
- package/types/src/FS.d.ts +709 -201
- package/types/src/FS.d.ts.map +1 -1
- package/types/src/Func.d.ts +455 -0
- package/types/src/Func.d.ts.map +1 -0
- package/types/src/Http.d.ts +374 -0
- package/types/src/Http.d.ts.map +1 -0
- package/types/src/Id.d.ts +200 -0
- package/types/src/Id.d.ts.map +1 -0
- package/types/src/Logger.d.ts +374 -24
- package/types/src/Logger.d.ts.map +1 -1
- package/types/src/Num.d.ts +578 -0
- package/types/src/Num.d.ts.map +1 -0
- package/types/src/Obj.d.ts +475 -0
- package/types/src/Obj.d.ts.map +1 -0
- package/types/src/SQLite.d.ts +647 -305
- package/types/src/SQLite.d.ts.map +1 -1
- package/types/src/Schema.d.ts +940 -0
- package/types/src/Schema.d.ts.map +1 -0
- package/types/src/Str.d.ts +696 -0
- package/types/src/Str.d.ts.map +1 -0
- package/types/src/Sys.d.ts +269 -0
- package/types/src/Sys.d.ts.map +1 -0
- package/types/src/Time.d.ts +664 -0
- package/types/src/Time.d.ts.map +1 -0
- package/types/src/Utils.d.ts +154 -102
- package/types/src/Utils.d.ts.map +1 -1
- package/types/src/errors.d.ts +292 -0
- package/types/src/errors.d.ts.map +1 -0
- package/tsconfig.json +0 -18
- package/types/index.d.ts.map +0 -1
package/src/Logger.js
CHANGED
|
@@ -1,307 +1,739 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A console logger that works with zero setup: levels, colors, a small
|
|
5
|
+
* markup for styling, groups, timers and tables. In production, switch to
|
|
6
|
+
* one JSON object per line with `LOG_FORMAT=json`, and write to rotating
|
|
7
|
+
* files if you need to.
|
|
8
|
+
*
|
|
9
|
+
* Markup: `<% red bold Error:%> disk is full`. Any style name works, plus
|
|
10
|
+
* `#ff8800`, `bg#1e1e2e`, `rgb(255, 128, 0)` and `bgRgb(...)`.
|
|
11
|
+
*
|
|
12
|
+
* Levels, from chatty to severe: `trace`, `debug`, `info`, `warn`, `error`,
|
|
13
|
+
* `fatal`. The default is `info`, or `debug` when `DEBUG` is set; `LOG_LEVEL`
|
|
14
|
+
* overrides it. Warnings and errors go to stderr.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* nc.info("Server listening on port 3000");
|
|
18
|
+
* nc.warn("Cache is almost full");
|
|
19
|
+
* nc.error(new Error("Payment failed", { cause: err }));
|
|
20
|
+
* nc.log("<% cyan bold Tip:%> press <% bgWhite black q %> to quit");
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const fs = require("node:fs");
|
|
24
|
+
const path = require("node:path");
|
|
25
|
+
const util = require("node:util");
|
|
26
|
+
const color = require("./Color.js");
|
|
27
|
+
const time = require("./Time.js");
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Log levels, from the most verbose to the most severe. `silent` hides everything.
|
|
31
|
+
* @typedef {"trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent"} LogLevel
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Where logs go: `process.stdout`, a file stream, or anything with a
|
|
36
|
+
* `write(text)` method.
|
|
37
|
+
* @typedef {{ write(text: string): unknown }} LogStream
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Writing logs to a file.
|
|
42
|
+
* @typedef {object} LogFileOptions
|
|
43
|
+
* @property {string} path The file to append to. Folders are created, colors removed.
|
|
44
|
+
* @property {string | number} [maxSize] Rotate past this size, like `"10MB"`.
|
|
45
|
+
* @property {number} [maxFiles] How many rotated files to keep. Defaults to `5`.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Options for `createLogger()` and `configure()`.
|
|
50
|
+
* @typedef {object} LoggerOptions
|
|
51
|
+
* @property {LogLevel} [level] Hide messages below this level. Defaults to `LOG_LEVEL`, else `"info"`.
|
|
52
|
+
* @property {string} [scope] Shown before each message, like `[db]`. Child loggers extend it (`db:pool`).
|
|
53
|
+
* @property {boolean | string} [timestamp] `true` shows `[HH:mm:ss]`, `false` hides it, a string is a `time.format` pattern. Defaults to `true`.
|
|
54
|
+
* @property {"pretty" | "json"} [format] `"json"` writes one object per line, for log collectors. Defaults to `LOG_FORMAT`, else `"pretty"`.
|
|
55
|
+
* @property {{ open?: string, close?: string }} [delimiter] Markup delimiters. Defaults to `<%` and `%>`.
|
|
56
|
+
* @property {boolean} [colors] Force colors on or off. By default, it depends on the terminal.
|
|
57
|
+
* @property {LogStream} [stdout] Where `trace` to `info` go. Defaults to `process.stdout`.
|
|
58
|
+
* @property {LogStream} [stderr] Where `warn`, `error` and `fatal` go. Defaults to `process.stderr`.
|
|
59
|
+
* @property {string | LogFileOptions} [file] Also write every message to a file.
|
|
60
|
+
* @property {Record<string, unknown>} [fields] Added to every JSON record, like a service name.
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A logger from `createLogger()`. Every method returns the logger, so calls chain.
|
|
65
|
+
*
|
|
66
|
+
* @typedef {object} Logger
|
|
67
|
+
* @property {(...args: unknown[]) => Logger} log A plain message, no badge. Supports markup.
|
|
68
|
+
* @property {(...args: unknown[]) => Logger} trace Very detailed diagnostics, hidden unless the level is `trace`.
|
|
69
|
+
* @property {(...args: unknown[]) => Logger} debug Diagnostics, hidden unless the level is `debug` or lower.
|
|
70
|
+
* @property {(...args: unknown[]) => Logger} info An `ℹ INFO` message.
|
|
71
|
+
* @property {(...args: unknown[]) => Logger} success A `✔ OK` message.
|
|
72
|
+
* @property {(...args: unknown[]) => Logger} warn A `⚠ WARN` message, on stderr.
|
|
73
|
+
* @property {(...args: unknown[]) => Logger} error An `✖ ERROR` message, on stderr. Errors show their stack and cause.
|
|
74
|
+
* @property {(...args: unknown[]) => Logger} fatal An `✖ FATAL` message, on stderr.
|
|
75
|
+
* @property {(label?: string) => Logger} group Prints a label and indents what follows. Groups nest.
|
|
76
|
+
* @property {() => Logger} groupEnd Closes the current group.
|
|
77
|
+
* @property {(label?: string) => Logger} timeStart Starts a named timer.
|
|
78
|
+
* @property {(label?: string) => Logger} timeEnd Prints how long since `timeStart(label)`.
|
|
79
|
+
* @property {(rows: Array<Record<string, unknown>> | unknown[][], options?: import("./Cli").TableOptions) => Logger} table Prints rows as a table.
|
|
80
|
+
* @property {(text: string, options?: import("./Cli").BoxOptions) => Logger} box Prints text in a box.
|
|
81
|
+
* @property {(title?: string) => Logger} divider Prints a horizontal line.
|
|
82
|
+
* @property {(scope: string, options?: LoggerOptions) => Logger} child A logger with the same settings and a nested scope. Its `fields` are added to the parent's.
|
|
83
|
+
* @property {(level: LogLevel) => Logger} setLevel Changes the minimum level.
|
|
84
|
+
* @property {() => LogLevel} getLevel The current minimum level.
|
|
85
|
+
* @property {(level: LogLevel) => boolean} isLevelEnabled Would this level be printed? Skip expensive debug output when it wouldn't.
|
|
86
|
+
* @property {(options: LoggerOptions) => Logger} configure Changes several settings at once.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/** @type {Record<LogLevel, number>} */
|
|
90
|
+
const LEVELS = { trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60, silent: Infinity };
|
|
91
|
+
|
|
92
|
+
/** @type {Record<string, { label: string, style: string, stream: "stdout" | "stderr", level: LogLevel }>} */
|
|
93
|
+
const BADGES = {
|
|
94
|
+
log: { label: "", style: "", stream: "stdout", level: "info" },
|
|
95
|
+
trace: { label: "… TRACE", style: "gray dim", stream: "stdout", level: "trace" },
|
|
96
|
+
debug: { label: "● DEBUG", style: "gray bold", stream: "stdout", level: "debug" },
|
|
97
|
+
info: { label: "ℹ INFO", style: "cyan bold", stream: "stdout", level: "info" },
|
|
98
|
+
success: { label: "✔ OK", style: "greenBright bold", stream: "stdout", level: "info" },
|
|
99
|
+
warn: { label: "⚠ WARN", style: "yellowBright bold", stream: "stderr", level: "warn" },
|
|
100
|
+
error: { label: "✖ ERROR", style: "redBright bold", stream: "stderr", level: "error" },
|
|
101
|
+
fatal: { label: "✖ FATAL", style: "bgRed whiteBright bold", stream: "stderr", level: "fatal" },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const STYLE_NAMES = new Set([
|
|
105
|
+
"reset", "bold", "dim", "italic", "underline", "overline", "inverse", "hidden", "strikethrough",
|
|
106
|
+
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "gray", "grey",
|
|
107
|
+
"blackBright", "redBright", "greenBright", "yellowBright", "blueBright", "magentaBright", "cyanBright", "whiteBright",
|
|
108
|
+
"bgBlack", "bgRed", "bgGreen", "bgYellow", "bgBlue", "bgMagenta", "bgCyan", "bgWhite", "bgGray", "bgGrey",
|
|
109
|
+
"bgBlackBright", "bgRedBright", "bgGreenBright", "bgYellowBright", "bgBlueBright", "bgMagentaBright", "bgCyanBright", "bgWhiteBright",
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
/** @returns {LogLevel} */
|
|
113
|
+
const _defaultLevel = () => {
|
|
114
|
+
const fromEnv = String(process.env.LOG_LEVEL ?? "").toLowerCase();
|
|
115
|
+
if (fromEnv in LEVELS) return /** @type {LogLevel} */ (fromEnv);
|
|
116
|
+
return process.env.DEBUG || process.env.NODE_DEBUG ? "debug" : "info";
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/** @param {string} value */
|
|
120
|
+
const _escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {import("./Color").ColorModule} palette
|
|
124
|
+
* @param {string[]} tokens
|
|
125
|
+
* @param {string} text
|
|
126
|
+
* @returns {string}
|
|
127
|
+
*/
|
|
128
|
+
const _style = (palette, tokens, text) => {
|
|
129
|
+
/** @type {any} */
|
|
130
|
+
let chain = palette;
|
|
131
|
+
for (const token of tokens) {
|
|
132
|
+
const name = token === "normal" ? "reset" : token;
|
|
133
|
+
let m;
|
|
134
|
+
if (STYLE_NAMES.has(name)) chain = chain[name];
|
|
135
|
+
else if ((m = /^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i.exec(name))) chain = chain.rgb(Number(m[1]), Number(m[2]), Number(m[3]));
|
|
136
|
+
else if ((m = /^bgrgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i.exec(name))) chain = chain.bgRgb(Number(m[1]), Number(m[2]), Number(m[3]));
|
|
137
|
+
else if (/^#[0-9a-f]{3,8}$/i.test(name)) chain = chain.hex(name);
|
|
138
|
+
else if (/^bg#[0-9a-f]{3,8}$/i.test(name)) chain = chain.bgHex(name.slice(2));
|
|
139
|
+
}
|
|
140
|
+
return chain === palette ? text : chain(text);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} token
|
|
145
|
+
*/
|
|
146
|
+
const _isStyleToken = (token) =>
|
|
147
|
+
STYLE_NAMES.has(token) ||
|
|
148
|
+
token === "normal" ||
|
|
149
|
+
/^(bg)?rgb\(\d{1,3},\d{1,3},\d{1,3}\)$/i.test(token) ||
|
|
150
|
+
/^(bg)?#[0-9a-f]{3,8}$/i.test(token);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Renders `<% styles text %>` markup.
|
|
154
|
+
* @param {string} input
|
|
155
|
+
* @param {{ open: string, close: string }} delimiter
|
|
156
|
+
* @param {import("./Color").ColorModule} palette
|
|
157
|
+
* @returns {string}
|
|
158
|
+
*/
|
|
159
|
+
const _markup = (input, delimiter, palette) => {
|
|
160
|
+
if (!input.includes(delimiter.open)) return input;
|
|
161
|
+
const regex = new RegExp(`${_escape(delimiter.open)}([\\s\\S]*?)${_escape(delimiter.close)}`, "g");
|
|
162
|
+
return input.replace(regex, (_, content) => {
|
|
163
|
+
const normalized = String(content).replace(/(bg)?rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/gi, (m0, bg, r, g, b) => `${bg ?? ""}rgb(${r},${g},${b})`);
|
|
164
|
+
/** @type {string[]} */
|
|
165
|
+
const tokens = [];
|
|
166
|
+
let rest = normalized.replace(/^\s+/, "");
|
|
167
|
+
for (;;) {
|
|
168
|
+
const match = /^(\S+)(\s+|$)/.exec(rest);
|
|
169
|
+
if (!match || !_isStyleToken(match[1])) break;
|
|
170
|
+
tokens.push(match[1]);
|
|
171
|
+
rest = rest.slice(match[0].length);
|
|
172
|
+
}
|
|
173
|
+
return _style(palette, tokens, rest);
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {unknown} value
|
|
179
|
+
* @param {boolean} colors
|
|
180
|
+
* @returns {string}
|
|
181
|
+
*/
|
|
182
|
+
const _stringify = (value, colors) => {
|
|
183
|
+
if (typeof value === "string") return value;
|
|
184
|
+
if (value instanceof Error) {
|
|
185
|
+
let text = value.stack ?? `${value.name}: ${value.message}`;
|
|
186
|
+
let cause = /** @type {any} */ (value).cause;
|
|
187
|
+
let depth = 0;
|
|
188
|
+
while (cause !== undefined && depth++ < 5) {
|
|
189
|
+
text += `\nCaused by: ${cause instanceof Error ? cause.stack ?? cause.message : util.inspect(cause, { colors })}`;
|
|
190
|
+
cause = cause instanceof Error ? /** @type {any} */ (cause).cause : undefined;
|
|
191
|
+
}
|
|
192
|
+
return text;
|
|
193
|
+
}
|
|
194
|
+
if (value !== null && typeof value === "object") {
|
|
195
|
+
const proto = Object.getPrototypeOf(value);
|
|
196
|
+
if (Array.isArray(value) || proto === Object.prototype || proto === null) {
|
|
197
|
+
try {
|
|
198
|
+
const json = JSON.stringify(value, (_, v) => (typeof v === "bigint" ? `${v}n` : v), 2);
|
|
199
|
+
if (json !== undefined) return json;
|
|
200
|
+
} catch {
|
|
201
|
+
// circular or exotic: fall back to util.inspect
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return util.inspect(value, { depth: 6, colors, breakLength: 100 });
|
|
205
|
+
}
|
|
206
|
+
return typeof value === "symbol" || typeof value === "function" ? util.inspect(value, { colors }) : String(value);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @param {string} level
|
|
211
|
+
* @param {unknown[]} args
|
|
212
|
+
* @param {string | undefined} scope
|
|
213
|
+
* @param {Record<string, unknown>} fields
|
|
214
|
+
* @returns {string}
|
|
215
|
+
*/
|
|
216
|
+
const _json = (level, args, scope, fields) => {
|
|
217
|
+
/** @type {Record<string, unknown>} */
|
|
218
|
+
const record = { time: new Date().toISOString(), level, ...fields };
|
|
219
|
+
if (scope) record.scope = scope;
|
|
220
|
+
const messages = [];
|
|
221
|
+
for (const arg of args) {
|
|
222
|
+
if (arg instanceof Error) {
|
|
223
|
+
record.err = { name: arg.name, message: arg.message, stack: arg.stack, code: /** @type {any} */ (arg).code, cause: /** @type {any} */ (arg).cause instanceof Error ? /** @type {any} */ (arg).cause.message : /** @type {any} */ (arg).cause };
|
|
224
|
+
} else if (arg !== null && typeof arg === "object" && !Array.isArray(arg)) {
|
|
225
|
+
Object.assign(record, arg);
|
|
226
|
+
} else {
|
|
227
|
+
messages.push(typeof arg === "string" ? color.strip(arg) : _stringify(arg, false));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
record.msg = messages.join(" ");
|
|
231
|
+
try {
|
|
232
|
+
return JSON.stringify(record, (_, v) => (typeof v === "bigint" ? v.toString() : v));
|
|
233
|
+
} catch {
|
|
234
|
+
return JSON.stringify({ time: record.time, level, msg: `${record.msg} [unserializable fields]` });
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Appends a line, rotating the file when it gets too big.
|
|
240
|
+
* @param {LogFileOptions} file
|
|
241
|
+
* @param {string} line
|
|
242
|
+
*/
|
|
243
|
+
const _writeFile = (file, line) => {
|
|
244
|
+
try {
|
|
245
|
+
const target = path.resolve(file.path);
|
|
246
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
247
|
+
if (file.maxSize !== undefined) {
|
|
248
|
+
const limit = typeof file.maxSize === "number" ? file.maxSize : require("./Num.js").parseBytes(file.maxSize);
|
|
249
|
+
let size = 0;
|
|
250
|
+
try {
|
|
251
|
+
size = fs.statSync(target).size;
|
|
252
|
+
} catch {
|
|
253
|
+
size = 0;
|
|
254
|
+
}
|
|
255
|
+
if (size > 0 && size + Buffer.byteLength(line) > limit) {
|
|
256
|
+
const keep = Math.max(1, file.maxFiles ?? 5);
|
|
257
|
+
for (let i = keep - 1; i >= 1; i--) {
|
|
258
|
+
if (fs.existsSync(`${target}.${i}`)) fs.renameSync(`${target}.${i}`, `${target}.${i + 1}`);
|
|
259
|
+
}
|
|
260
|
+
if (fs.existsSync(`${target}.${keep + 1}`)) fs.rmSync(`${target}.${keep + 1}`);
|
|
261
|
+
fs.renameSync(target, `${target}.1`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
fs.appendFileSync(target, `${line}\n`);
|
|
265
|
+
} catch {
|
|
266
|
+
// Logging must never crash the application.
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @param {LoggerOptions} options
|
|
272
|
+
* @returns {Logger}
|
|
273
|
+
*/
|
|
274
|
+
const _create = (options) => {
|
|
275
|
+
const settings = {
|
|
276
|
+
level: options.level ?? _defaultLevel(),
|
|
277
|
+
scope: options.scope,
|
|
278
|
+
timestamp: options.timestamp ?? true,
|
|
279
|
+
format: options.format ?? (process.env.LOG_FORMAT === "json" ? "json" : "pretty"),
|
|
280
|
+
delimiter: { open: "<%", close: "%>", ...options.delimiter },
|
|
281
|
+
colors: options.colors,
|
|
282
|
+
stdout: options.stdout,
|
|
283
|
+
stderr: options.stderr,
|
|
284
|
+
file: typeof options.file === "string" ? { path: options.file } : options.file,
|
|
285
|
+
fields: options.fields ?? {},
|
|
286
|
+
};
|
|
287
|
+
/** @type {string[]} */
|
|
288
|
+
const groups = [];
|
|
289
|
+
/** @type {Map<string, bigint>} */
|
|
290
|
+
const timers = new Map();
|
|
291
|
+
|
|
292
|
+
/** @param {"stdout" | "stderr"} which */
|
|
293
|
+
const streamOf = (which) => (which === "stderr" ? settings.stderr ?? process.stderr : settings.stdout ?? process.stdout);
|
|
294
|
+
|
|
295
|
+
/** @param {"stdout" | "stderr"} which */
|
|
296
|
+
const paletteOf = (which) => {
|
|
297
|
+
if (settings.colors === true) return color.create(color.level > 0 ? color.level : 3);
|
|
298
|
+
if (settings.colors === false) return color.create(0);
|
|
299
|
+
const stream = streamOf(which);
|
|
300
|
+
return stream === process.stdout || stream === process.stderr ? color.create(color.detect(/** @type {any} */ (stream))) : color.create(0);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const plain = color.create(0);
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @param {keyof typeof BADGES} kind
|
|
307
|
+
* @param {unknown[]} args
|
|
308
|
+
*/
|
|
309
|
+
const emit = (kind, args) => {
|
|
310
|
+
const badge = BADGES[kind];
|
|
311
|
+
if (LEVELS[badge.level] < LEVELS[settings.level] || settings.level === "silent") return;
|
|
312
|
+
if (settings.format === "json") {
|
|
313
|
+
const line = _json(kind === "log" ? "info" : kind, args, settings.scope, settings.fields);
|
|
314
|
+
streamOf(badge.stream).write(`${line}\n`);
|
|
315
|
+
if (settings.file) _writeFile(settings.file, line);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const render = (/** @type {import("./Color").ColorModule} */ palette) => {
|
|
319
|
+
const colors = palette.level > 0;
|
|
320
|
+
const stamp = settings.timestamp
|
|
321
|
+
? _style(palette, ["gray"], `[${time.format(new Date(), typeof settings.timestamp === "string" ? settings.timestamp : "HH:mm:ss")}]`)
|
|
322
|
+
: "";
|
|
323
|
+
const scope = settings.scope ? _style(palette, ["magenta"], `[${settings.scope}]`) : "";
|
|
324
|
+
const label = badge.label ? _style(palette, badge.style.split(" "), badge.label) : "";
|
|
325
|
+
const body = args
|
|
326
|
+
.map((arg) => _markup(_stringify(arg, colors), settings.delimiter, palette))
|
|
327
|
+
.map((text) => (kind === "debug" || kind === "trace" ? _style(palette, ["gray"], text) : text))
|
|
328
|
+
.join(" ");
|
|
329
|
+
const indent = " ".repeat(groups.length);
|
|
330
|
+
const tags = [scope, label].filter(Boolean).join(" ");
|
|
331
|
+
const prefix = `${stamp ? `${stamp} ` : ""}${indent}${tags ? `${tags} ` : ""}`;
|
|
332
|
+
const lines = body.replace(/^(\s*\r?\n)+|(\r?\n\s*)+$/g, "").split(/\r?\n/);
|
|
333
|
+
const pad = " ".repeat(color.width(stamp ? `${stamp} ` : "") + indent.length);
|
|
334
|
+
return lines.map((line, i) => (i === 0 ? `${prefix}${line}`.trimEnd() : pad + line)).join("\n");
|
|
335
|
+
};
|
|
336
|
+
streamOf(badge.stream).write(`${render(paletteOf(badge.stream))}\n`);
|
|
337
|
+
if (settings.file) _writeFile(settings.file, render(plain));
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
/** @type {Logger} */
|
|
341
|
+
const logger = {
|
|
342
|
+
log: (...args) => (emit("log", args), logger),
|
|
343
|
+
trace: (...args) => (emit("trace", args), logger),
|
|
344
|
+
debug: (...args) => (emit("debug", args), logger),
|
|
345
|
+
info: (...args) => (emit("info", args), logger),
|
|
346
|
+
success: (...args) => (emit("success", args), logger),
|
|
347
|
+
warn: (...args) => (emit("warn", args), logger),
|
|
348
|
+
error: (...args) => (emit("error", args), logger),
|
|
349
|
+
fatal: (...args) => (emit("fatal", args), logger),
|
|
350
|
+
group: (label = "") => {
|
|
351
|
+
emit("log", [`▼ ${label}`.trimEnd()]);
|
|
352
|
+
groups.push(label);
|
|
353
|
+
return logger;
|
|
354
|
+
},
|
|
355
|
+
groupEnd: () => {
|
|
356
|
+
groups.pop();
|
|
357
|
+
return logger;
|
|
358
|
+
},
|
|
359
|
+
timeStart: (label = "default") => {
|
|
360
|
+
timers.set(label, process.hrtime.bigint());
|
|
361
|
+
return logger;
|
|
362
|
+
},
|
|
363
|
+
timeEnd: (label = "default") => {
|
|
364
|
+
const start = timers.get(label);
|
|
365
|
+
if (start === undefined) return logger.warn(`Timer "${label}" does not exist`);
|
|
366
|
+
timers.delete(label);
|
|
367
|
+
const ms = Number(process.hrtime.bigint() - start) / 1e6;
|
|
368
|
+
return logger.log(`${label}: ${ms < 1000 ? `${Math.round(ms * 100) / 100}ms` : time.formatDuration(ms, { units: 2 })}`);
|
|
369
|
+
},
|
|
370
|
+
table: (rows, tableOptions) => logger.log(require("./Cli.js").table(rows, { ...tableOptions, colors: paletteOf("stdout").level > 0 })),
|
|
371
|
+
box: (text, boxOptions) => logger.log(require("./Cli.js").box(text, { ...boxOptions, colors: paletteOf("stdout").level > 0 })),
|
|
372
|
+
divider: (title) => {
|
|
373
|
+
const columns = /** @type {any} */ (streamOf("stdout")).columns ?? 80;
|
|
374
|
+
const width = Math.max(10, Math.min(columns, 100) - (settings.timestamp ? 11 : 0) - groups.length * 2);
|
|
375
|
+
const text = title ? `── ${title} ${"─".repeat(Math.max(0, width - color.width(title) - 4))}` : "─".repeat(width);
|
|
376
|
+
return logger.log(`${settings.delimiter.open}gray ${text}${settings.delimiter.close}`);
|
|
377
|
+
},
|
|
378
|
+
child: (scope, childOptions = {}) =>
|
|
379
|
+
_create({
|
|
380
|
+
...settings,
|
|
381
|
+
...childOptions,
|
|
382
|
+
fields: { ...settings.fields, ...childOptions.fields },
|
|
383
|
+
scope: settings.scope ? `${settings.scope}:${scope}` : scope,
|
|
384
|
+
}),
|
|
385
|
+
setLevel: (level) => {
|
|
386
|
+
if (!(level in LEVELS)) throw new RangeError(`Unknown log level "${level}"`);
|
|
387
|
+
settings.level = level;
|
|
388
|
+
return logger;
|
|
389
|
+
},
|
|
390
|
+
getLevel: () => settings.level,
|
|
391
|
+
isLevelEnabled: (level) => settings.level !== "silent" && LEVELS[level] >= LEVELS[settings.level],
|
|
392
|
+
configure: (next) => {
|
|
393
|
+
if (next.level !== undefined) logger.setLevel(next.level);
|
|
394
|
+
if (next.scope !== undefined) settings.scope = next.scope;
|
|
395
|
+
if (next.timestamp !== undefined) settings.timestamp = next.timestamp;
|
|
396
|
+
if (next.format !== undefined) settings.format = next.format;
|
|
397
|
+
if (next.delimiter !== undefined) settings.delimiter = { ...settings.delimiter, ...next.delimiter };
|
|
398
|
+
if (next.colors !== undefined) settings.colors = next.colors;
|
|
399
|
+
if (next.stdout !== undefined) settings.stdout = next.stdout;
|
|
400
|
+
if (next.stderr !== undefined) settings.stderr = next.stderr;
|
|
401
|
+
if (next.file !== undefined) settings.file = typeof next.file === "string" ? { path: next.file } : next.file;
|
|
402
|
+
if (next.fields !== undefined) settings.fields = next.fields;
|
|
403
|
+
return logger;
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
return logger;
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const _default = _create({});
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Creates a logger with its own settings.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* const log = nc.createLogger({ scope: "api", timestamp: "HH:mm:ss.SSS" });
|
|
416
|
+
* log.info("GET /users 200"); // [14:30:05.120] [api] ℹ INFO GET /users 200
|
|
417
|
+
* log.child("db").debug("query took 12ms");
|
|
418
|
+
*
|
|
419
|
+
* const prod = nc.createLogger({ format: "json", fields: { service: "billing" } });
|
|
420
|
+
* prod.error("charge failed", { orderId: 42 }, error);
|
|
421
|
+
*
|
|
422
|
+
* @param {LoggerOptions} [options]
|
|
423
|
+
* @returns {Logger}
|
|
424
|
+
*/
|
|
425
|
+
function createLogger(options = {}) {
|
|
426
|
+
return _create(options);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Prints a message without a badge. Strings support markup, objects are
|
|
431
|
+
* pretty-printed, and several arguments are joined with spaces.
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* nc.log("<% green ✔ Saved %> in <% bold 12ms %>");
|
|
435
|
+
* nc.log("user:", { id: 1, roles: ["admin"] });
|
|
436
|
+
*
|
|
437
|
+
* @param {...unknown} args
|
|
438
|
+
* @returns {typeof import("./Logger")}
|
|
439
|
+
*/
|
|
440
|
+
function log(...args) {
|
|
441
|
+
_default.log(...args);
|
|
442
|
+
return module.exports;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Very detailed diagnostics, shown only at the `trace` level.
|
|
447
|
+
*
|
|
448
|
+
* @param {...unknown} args
|
|
449
|
+
* @returns {typeof import("./Logger")}
|
|
450
|
+
*/
|
|
451
|
+
function trace(...args) {
|
|
452
|
+
_default.trace(...args);
|
|
453
|
+
return module.exports;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Diagnostics for developers, shown at the `debug` level (the default when
|
|
458
|
+
* `DEBUG` is set).
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* nc.debug("cache miss", { key });
|
|
462
|
+
*
|
|
463
|
+
* @param {...unknown} args
|
|
464
|
+
* @returns {typeof import("./Logger")}
|
|
465
|
+
*/
|
|
466
|
+
function debug(...args) {
|
|
467
|
+
_default.debug(...args);
|
|
468
|
+
return module.exports;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* An informational message.
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* nc.info("Server listening on http://localhost:3000");
|
|
476
|
+
*
|
|
477
|
+
* @param {...unknown} args
|
|
478
|
+
* @returns {typeof import("./Logger")}
|
|
479
|
+
*/
|
|
480
|
+
function info(...args) {
|
|
481
|
+
_default.info(...args);
|
|
482
|
+
return module.exports;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* A success message.
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* nc.success("Database connected");
|
|
490
|
+
*
|
|
491
|
+
* @param {...unknown} args
|
|
492
|
+
* @returns {typeof import("./Logger")}
|
|
493
|
+
*/
|
|
494
|
+
function success(...args) {
|
|
495
|
+
_default.success(...args);
|
|
496
|
+
return module.exports;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* A warning, written to stderr.
|
|
501
|
+
*
|
|
502
|
+
* @param {...unknown} args
|
|
503
|
+
* @returns {typeof import("./Logger")}
|
|
504
|
+
*/
|
|
505
|
+
function warn(...args) {
|
|
506
|
+
_default.warn(...args);
|
|
507
|
+
return module.exports;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* An error, written to stderr. Error objects show their stack trace and
|
|
512
|
+
* their chain of causes.
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* nc.error(new Error("Cannot save order", { cause: dbError }));
|
|
516
|
+
*
|
|
517
|
+
* @param {...unknown} args
|
|
518
|
+
* @returns {typeof import("./Logger")}
|
|
519
|
+
*/
|
|
520
|
+
function error(...args) {
|
|
521
|
+
_default.error(...args);
|
|
522
|
+
return module.exports;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* A fatal error, written to stderr. It doesn't stop the process; call
|
|
527
|
+
* `process.exit(1)` yourself if you mean to.
|
|
528
|
+
*
|
|
529
|
+
* @param {...unknown} args
|
|
530
|
+
* @returns {typeof import("./Logger")}
|
|
531
|
+
*/
|
|
532
|
+
function fatal(...args) {
|
|
533
|
+
_default.fatal(...args);
|
|
534
|
+
return module.exports;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Prints a label and indents what follows, until `groupEnd()`. Groups nest.
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* nc.group("Startup").info("Loading config");
|
|
542
|
+
* nc.group("Database").success("Connected").groupEnd();
|
|
543
|
+
* nc.groupEnd();
|
|
544
|
+
*
|
|
545
|
+
* @param {string} [label]
|
|
546
|
+
* @returns {typeof import("./Logger")}
|
|
547
|
+
*/
|
|
548
|
+
function group(label) {
|
|
549
|
+
_default.group(label);
|
|
550
|
+
return module.exports;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Closes the current group.
|
|
555
|
+
*
|
|
556
|
+
* @returns {typeof import("./Logger")}
|
|
557
|
+
*/
|
|
558
|
+
function groupEnd() {
|
|
559
|
+
_default.groupEnd();
|
|
560
|
+
return module.exports;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Starts a named timer. `timeEnd()` prints the elapsed time.
|
|
565
|
+
*
|
|
566
|
+
* @example
|
|
567
|
+
* nc.timeStart("import");
|
|
568
|
+
* await importProducts();
|
|
569
|
+
* nc.timeEnd("import"); // "import: 1.24s"
|
|
570
|
+
*
|
|
571
|
+
* @param {string} [label="default"]
|
|
572
|
+
* @returns {typeof import("./Logger")}
|
|
573
|
+
*/
|
|
574
|
+
function timeStart(label) {
|
|
575
|
+
_default.timeStart(label);
|
|
576
|
+
return module.exports;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Prints the time since `timeStart()` with the same label.
|
|
581
|
+
*
|
|
582
|
+
* @param {string} [label="default"]
|
|
583
|
+
* @returns {typeof import("./Logger")}
|
|
584
|
+
*/
|
|
585
|
+
function timeEnd(label) {
|
|
586
|
+
_default.timeEnd(label);
|
|
587
|
+
return module.exports;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Prints rows as a table.
|
|
592
|
+
*
|
|
593
|
+
* @example
|
|
594
|
+
* nc.table([{ name: "Ada", role: "admin" }, { name: "Bob", role: "user" }]);
|
|
595
|
+
*
|
|
596
|
+
* @param {Array<Record<string, unknown>> | unknown[][]} rows
|
|
597
|
+
* @param {import("./Cli").TableOptions} [options]
|
|
598
|
+
* @returns {typeof import("./Logger")}
|
|
599
|
+
*/
|
|
600
|
+
function table(rows, options) {
|
|
601
|
+
_default.table(rows, options);
|
|
602
|
+
return module.exports;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Prints text in a box. Nice for startup banners.
|
|
607
|
+
*
|
|
608
|
+
* @example
|
|
609
|
+
* nc.box("Server ready\nhttp://localhost:3000", { title: "my-app", borderColor: "green" });
|
|
610
|
+
*
|
|
611
|
+
* @param {string} text
|
|
612
|
+
* @param {import("./Cli").BoxOptions} [options]
|
|
613
|
+
* @returns {typeof import("./Logger")}
|
|
614
|
+
*/
|
|
615
|
+
function box(text, options) {
|
|
616
|
+
_default.box(text, options);
|
|
617
|
+
return module.exports;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Prints a horizontal line, with an optional title in it.
|
|
622
|
+
*
|
|
623
|
+
* @param {string} [title]
|
|
624
|
+
* @returns {typeof import("./Logger")}
|
|
625
|
+
*/
|
|
626
|
+
function divider(title) {
|
|
627
|
+
_default.divider(title);
|
|
628
|
+
return module.exports;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Sets the minimum level.
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* nc.setLevel("warn"); // warnings and errors only
|
|
636
|
+
* nc.setLevel("silent"); // nothing
|
|
637
|
+
*
|
|
638
|
+
* @param {LogLevel} level
|
|
639
|
+
* @returns {typeof import("./Logger")}
|
|
640
|
+
* @throws {RangeError} For an unknown level.
|
|
641
|
+
*/
|
|
642
|
+
function setLevel(level) {
|
|
643
|
+
_default.setLevel(level);
|
|
644
|
+
return module.exports;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* The current minimum level.
|
|
649
|
+
*
|
|
650
|
+
* @returns {LogLevel}
|
|
651
|
+
*/
|
|
652
|
+
function getLevel() {
|
|
653
|
+
return _default.getLevel();
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Would this level be printed? Use it to skip building expensive debug
|
|
658
|
+
* output.
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* if (nc.isLevelEnabled("debug")) nc.debug(buildHugeReport());
|
|
662
|
+
*
|
|
663
|
+
* @param {LogLevel} level
|
|
664
|
+
* @returns {boolean}
|
|
665
|
+
*/
|
|
666
|
+
function isLevelEnabled(level) {
|
|
667
|
+
return _default.isLevelEnabled(level);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Changes several settings at once.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* nc.configure({ level: "debug", file: "logs/app.log" });
|
|
675
|
+
* nc.configure({ format: "json", fields: { service: "api" } });
|
|
676
|
+
*
|
|
677
|
+
* @param {LoggerOptions} options
|
|
678
|
+
* @returns {typeof import("./Logger")}
|
|
679
|
+
*/
|
|
680
|
+
function configure(options) {
|
|
681
|
+
_default.configure(options);
|
|
682
|
+
return module.exports;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Shows or hides timestamps, or sets their pattern.
|
|
687
|
+
*
|
|
688
|
+
* @example
|
|
689
|
+
* nc.setTimestamp(false);
|
|
690
|
+
* nc.setTimestamp("YYYY-MM-DD HH:mm:ss.SSS");
|
|
691
|
+
*
|
|
692
|
+
* @param {boolean | string} value
|
|
693
|
+
* @returns {typeof import("./Logger")}
|
|
694
|
+
*/
|
|
695
|
+
function setTimestamp(value) {
|
|
696
|
+
_default.configure({ timestamp: value });
|
|
697
|
+
return module.exports;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Changes the markup delimiters, for when `<%` clashes with a template
|
|
702
|
+
* engine.
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* nc.setDelimiter({ open: "{{", close: "}}" });
|
|
706
|
+
* nc.log("{{red Hello}} world");
|
|
707
|
+
*
|
|
708
|
+
* @param {{ open?: string, close?: string }} [options]
|
|
709
|
+
* @returns {typeof import("./Logger")}
|
|
710
|
+
*/
|
|
711
|
+
function setDelimiter(options = {}) {
|
|
712
|
+
_default.configure({ delimiter: options });
|
|
713
|
+
return module.exports;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
module.exports = {
|
|
717
|
+
log,
|
|
718
|
+
trace,
|
|
719
|
+
debug,
|
|
720
|
+
info,
|
|
721
|
+
success,
|
|
722
|
+
warn,
|
|
723
|
+
error,
|
|
724
|
+
fatal,
|
|
725
|
+
group,
|
|
726
|
+
groupEnd,
|
|
727
|
+
timeStart,
|
|
728
|
+
timeEnd,
|
|
729
|
+
table,
|
|
730
|
+
box,
|
|
731
|
+
divider,
|
|
732
|
+
setLevel,
|
|
733
|
+
getLevel,
|
|
734
|
+
isLevelEnabled,
|
|
735
|
+
configure,
|
|
736
|
+
setTimestamp,
|
|
737
|
+
setDelimiter,
|
|
738
|
+
createLogger,
|
|
739
|
+
};
|