@holz/ansi-terminal-backend 0.7.0 → 0.8.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/holz-ansi-terminal-backend.cjs +1 -1
- package/dist/holz-ansi-terminal-backend.d.ts +1 -1
- package/dist/holz-ansi-terminal-backend.js +24 -28
- package/package.json +6 -5
- package/src/__tests__/ansi-terminal-backend.test.ts +8 -4
- package/src/ansi-codes.ts +2 -3
- package/src/ansi-terminal-backend.ts +17 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("@holz/core"),o=n=>`\x1B[${n}`,t=o("0m"),p=o("1m"),$=o("2m"),d=o("31m"),S=o("32m"),v=o("33m"),b=o("34m"),f=o("97m"),A=(n={})=>{const r=n.console??console,i=" ".repeat(5);return e=>{const a=h(new Date(e.timestamp)),l=`${t}${$}${a}${t}`,m=[{include:!0,command:"%s",content:l},{include:!0,command:"%s",content:T[e.level]},{include:!0,command:"%s",content:e.message.replace(/(\r?\n)/g,`$1${l} ${i} `)},{include:Object.keys(e.context).length>0,command:"%O",content:e.context},{include:e.origin.length>0,command:"%s",content:`${$}${e.origin.join(":")}${t}`}].filter(s=>s.include),u=m.map(s=>s.command).join(" "),g=m.map(s=>s.content);r.error(u,...g)}},h=n=>{const r=n.getHours().toString().padStart(2,"0"),i=n.getMinutes().toString().padStart(2,"0"),e=n.getSeconds().toString().padStart(2,"0"),a=n.getMilliseconds().toString().padStart(3,"0");return`[${r}:${i}:${e}.${a}]`},T={[c.level.trace]:`${f}TRACE${t}`,[c.level.debug]:`${b}DEBUG${t}`,[c.level.info]:`${S}INFO${t} `,[c.level.warn]:`${v}WARN${t} `,[c.level.error]:`${d}ERROR${t}`,[c.level.fatal]:`${p}${d}FATAL${t}`};exports.createAnsiTerminalBackend=A;
|
|
@@ -9,7 +9,7 @@ import { LogProcessor } from '@holz/core';
|
|
|
9
9
|
* ques, the printed text is much less understandable. It is better to check
|
|
10
10
|
* when constructing the logger instead.
|
|
11
11
|
*/
|
|
12
|
-
export declare
|
|
12
|
+
export declare const createAnsiTerminalBackend: (options?: Options) => LogProcessor;
|
|
13
13
|
|
|
14
14
|
declare interface Options {
|
|
15
15
|
/**
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
function v(t = {}) {
|
|
7
|
-
const r = t.console ?? console, i = " ".repeat(s.Error.length);
|
|
8
|
-
return (n) => {
|
|
9
|
-
const m = b(/* @__PURE__ */ new Date()), a = `${e}${u}${m}${e}`, l = [
|
|
1
|
+
import { level as c } from "@holz/core";
|
|
2
|
+
const o = (e) => `\x1B[${e}`, n = o("0m"), g = o("1m"), l = o("2m"), d = o("31m"), S = o("32m"), b = o("33m"), f = o("34m"), h = o("97m"), v = (e = {}) => {
|
|
3
|
+
const r = e.console ?? console, m = " ".repeat(5);
|
|
4
|
+
return (t) => {
|
|
5
|
+
const i = A(new Date(t.timestamp)), a = `${n}${l}${i}${n}`, $ = [
|
|
10
6
|
{
|
|
11
7
|
include: !0,
|
|
12
8
|
command: "%s",
|
|
@@ -15,39 +11,39 @@ function v(t = {}) {
|
|
|
15
11
|
{
|
|
16
12
|
include: !0,
|
|
17
13
|
command: "%s",
|
|
18
|
-
content:
|
|
14
|
+
content: x[t.level]
|
|
19
15
|
},
|
|
20
16
|
{
|
|
21
17
|
include: !0,
|
|
22
18
|
command: "%s",
|
|
23
|
-
content:
|
|
19
|
+
content: t.message.replace(
|
|
24
20
|
/(\r?\n)/g,
|
|
25
|
-
`$1${a} ${
|
|
21
|
+
`$1${a} ${m} `
|
|
26
22
|
)
|
|
27
23
|
},
|
|
28
24
|
{
|
|
29
|
-
include: Object.keys(
|
|
25
|
+
include: Object.keys(t.context).length > 0,
|
|
30
26
|
command: "%O",
|
|
31
|
-
content:
|
|
27
|
+
content: t.context
|
|
32
28
|
},
|
|
33
29
|
{
|
|
34
|
-
include:
|
|
30
|
+
include: t.origin.length > 0,
|
|
35
31
|
command: "%s",
|
|
36
|
-
content: `${
|
|
32
|
+
content: `${l}${t.origin.join(":")}${n}`
|
|
37
33
|
}
|
|
38
|
-
].filter((
|
|
39
|
-
r.error(
|
|
34
|
+
].filter((s) => s.include), u = $.map((s) => s.command).join(" "), p = $.map((s) => s.content);
|
|
35
|
+
r.error(u, ...p);
|
|
40
36
|
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
[
|
|
48
|
-
[
|
|
49
|
-
[
|
|
50
|
-
[
|
|
37
|
+
}, A = (e) => {
|
|
38
|
+
const r = e.getHours().toString().padStart(2, "0"), m = e.getMinutes().toString().padStart(2, "0"), t = e.getSeconds().toString().padStart(2, "0"), i = e.getMilliseconds().toString().padStart(3, "0");
|
|
39
|
+
return `[${r}:${m}:${t}.${i}]`;
|
|
40
|
+
}, x = {
|
|
41
|
+
[c.trace]: `${h}TRACE${n}`,
|
|
42
|
+
[c.debug]: `${f}DEBUG${n}`,
|
|
43
|
+
[c.info]: `${S}INFO${n} `,
|
|
44
|
+
[c.warn]: `${b}WARN${n} `,
|
|
45
|
+
[c.error]: `${d}ERROR${n}`,
|
|
46
|
+
[c.fatal]: `${g}${d}FATAL${n}`
|
|
51
47
|
};
|
|
52
48
|
export {
|
|
53
49
|
v as createAnsiTerminalBackend
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holz/ansi-terminal-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-rc.2",
|
|
4
4
|
"description": "An ANSI terminal backend for Holz",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -36,16 +36,17 @@
|
|
|
36
36
|
"test:types": "tsc"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@holz/core": "^0.
|
|
39
|
+
"@holz/core": "^0.8.0-rc.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@holz/core": "^0.
|
|
42
|
+
"@holz/core": "^0.8.0-rc.2",
|
|
43
43
|
"@types/node": "^22.0.0",
|
|
44
44
|
"@vitest/coverage-v8": "^3.0.8",
|
|
45
|
-
"typescript": "^5.
|
|
45
|
+
"typescript": "^5.8.2",
|
|
46
46
|
"vite": "^6.0.0",
|
|
47
47
|
"vite-plugin-dts": "^4.5.3",
|
|
48
48
|
"vite-tsconfig-paths": "^5.1.4",
|
|
49
49
|
"vitest": "^3.0.8"
|
|
50
|
-
}
|
|
50
|
+
},
|
|
51
|
+
"stableVersion": "0.7.0"
|
|
51
52
|
}
|
|
@@ -6,7 +6,7 @@ import { createAnsiTerminalBackend } from '../ansi-terminal-backend';
|
|
|
6
6
|
const CURRENT_TIME = new Date('2020-06-15T03:05:07.010Z');
|
|
7
7
|
|
|
8
8
|
describe('ANSI terminal backend', () => {
|
|
9
|
-
|
|
9
|
+
const createStream = () => {
|
|
10
10
|
let output = '';
|
|
11
11
|
const stream = new Writable({
|
|
12
12
|
write(chunk, _encoding, callback) {
|
|
@@ -19,10 +19,10 @@ describe('ANSI terminal backend', () => {
|
|
|
19
19
|
getOutput: () => output,
|
|
20
20
|
stream,
|
|
21
21
|
};
|
|
22
|
-
}
|
|
22
|
+
};
|
|
23
23
|
|
|
24
24
|
// Named "terminal" to avoid conflict with `global.console`.
|
|
25
|
-
|
|
25
|
+
const createTerminal = () => {
|
|
26
26
|
const stdout = createStream();
|
|
27
27
|
const stderr = createStream();
|
|
28
28
|
const terminal = new Console({
|
|
@@ -35,7 +35,7 @@ describe('ANSI terminal backend', () => {
|
|
|
35
35
|
stderr,
|
|
36
36
|
terminal,
|
|
37
37
|
};
|
|
38
|
-
}
|
|
38
|
+
};
|
|
39
39
|
|
|
40
40
|
beforeEach(() => {
|
|
41
41
|
vi.useFakeTimers({
|
|
@@ -62,15 +62,19 @@ describe('ANSI terminal backend', () => {
|
|
|
62
62
|
const backend = createAnsiTerminalBackend({ console: terminal });
|
|
63
63
|
|
|
64
64
|
const logger = createLogger(backend);
|
|
65
|
+
logger.trace('scream');
|
|
65
66
|
logger.debug('shout');
|
|
66
67
|
logger.info('normal');
|
|
67
68
|
logger.warn('hmmmm');
|
|
68
69
|
logger.error('oh no');
|
|
70
|
+
logger.fatal('goodbye');
|
|
69
71
|
|
|
72
|
+
expect(stderr.getOutput()).toContain('TRACE');
|
|
70
73
|
expect(stderr.getOutput()).toContain('DEBUG');
|
|
71
74
|
expect(stderr.getOutput()).toContain('INFO');
|
|
72
75
|
expect(stderr.getOutput()).toContain('WARN');
|
|
73
76
|
expect(stderr.getOutput()).toContain('ERROR');
|
|
77
|
+
expect(stderr.getOutput()).toContain('FATAL');
|
|
74
78
|
});
|
|
75
79
|
|
|
76
80
|
it('includes the log namespace', () => {
|
package/src/ansi-codes.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
return `\x1b[${code}`;
|
|
3
|
-
}
|
|
1
|
+
const ansiCode = (code: string) => `\x1b[${code}`;
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Assumes 3-bit color support for an ANSI terminal. This should work on most
|
|
@@ -19,3 +17,4 @@ export const blue = ansiCode('34m');
|
|
|
19
17
|
export const magenta = ansiCode('35m');
|
|
20
18
|
export const cyan = ansiCode('36m');
|
|
21
19
|
export const white = ansiCode('37m');
|
|
20
|
+
export const brightWhite = ansiCode('97m');
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { LogLevel } from '@holz/core';
|
|
1
|
+
import { level, type LogLevel, type Log, type LogProcessor } from '@holz/core';
|
|
3
2
|
import * as ansi from './ansi-codes';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -11,12 +10,14 @@ import * as ansi from './ansi-codes';
|
|
|
11
10
|
* ques, the printed text is much less understandable. It is better to check
|
|
12
11
|
* when constructing the logger instead.
|
|
13
12
|
*/
|
|
14
|
-
export
|
|
13
|
+
export const createAnsiTerminalBackend = (
|
|
14
|
+
options: Options = {},
|
|
15
|
+
): LogProcessor => {
|
|
15
16
|
const output = options.console ?? console;
|
|
16
|
-
const labelSizeInWhitespace = ' '.repeat(
|
|
17
|
+
const labelSizeInWhitespace = ' '.repeat(5); // char length of longest level type
|
|
17
18
|
|
|
18
19
|
return (log: Log) => {
|
|
19
|
-
const timestamp = formatAsTimestamp(new Date());
|
|
20
|
+
const timestamp = formatAsTimestamp(new Date(log.timestamp));
|
|
20
21
|
const timestampPrefix = `${ansi.reset}${ansi.dim}${timestamp}${ansi.reset}`;
|
|
21
22
|
const segments = [
|
|
22
23
|
{
|
|
@@ -55,24 +56,27 @@ export function createAnsiTerminalBackend(options: Options = {}): LogProcessor {
|
|
|
55
56
|
// CLIs typically print interactive messages to stdout and logs to stderr.
|
|
56
57
|
output.error(format, ...values);
|
|
57
58
|
};
|
|
58
|
-
}
|
|
59
|
+
};
|
|
59
60
|
|
|
60
|
-
//
|
|
61
|
-
|
|
61
|
+
// This is an interactive TTY, so we can assume someone is watching. They
|
|
62
|
+
// probably know what day it is. Focus on the time.
|
|
63
|
+
const formatAsTimestamp = (date: Date) => {
|
|
62
64
|
const hours = date.getHours().toString().padStart(2, '0');
|
|
63
65
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
64
66
|
const seconds = date.getSeconds().toString().padStart(2, '0');
|
|
65
67
|
const milliseconds = date.getMilliseconds().toString().padStart(3, '0');
|
|
66
68
|
|
|
67
69
|
return `[${hours}:${minutes}:${seconds}.${milliseconds}]`;
|
|
68
|
-
}
|
|
70
|
+
};
|
|
69
71
|
|
|
70
72
|
// Trailing whitespace is important for alignment.
|
|
71
73
|
const logLevelLabel: Record<LogLevel, string> = {
|
|
72
|
-
[
|
|
73
|
-
[
|
|
74
|
-
[
|
|
75
|
-
[
|
|
74
|
+
[level.trace]: `${ansi.brightWhite}TRACE${ansi.reset}`,
|
|
75
|
+
[level.debug]: `${ansi.blue}DEBUG${ansi.reset}`,
|
|
76
|
+
[level.info]: `${ansi.green}INFO${ansi.reset} `,
|
|
77
|
+
[level.warn]: `${ansi.yellow}WARN${ansi.reset} `,
|
|
78
|
+
[level.error]: `${ansi.red}ERROR${ansi.reset}`,
|
|
79
|
+
[level.fatal]: `${ansi.bold}${ansi.red}FATAL${ansi.reset}`,
|
|
76
80
|
};
|
|
77
81
|
|
|
78
82
|
interface Options {
|