Skip to content

Commit dddabc0

Browse files
committed
chore: migrate to node compat ts
1 parent 54bd548 commit dddabc0

16 files changed

Lines changed: 684 additions & 32 deletions

cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import os from 'node:os';
55
import pump from 'pump';
66
import {cosmiconfigSync} from 'cosmiconfig';
77
import meow from 'meow';
8-
import type {PrettifyOptions} from './lib/utils/types.js';
9-
import {build} from './index.js';
8+
import type {PrettifyOptions} from './lib/utils/types.ts';
9+
import {build} from './index.ts';
1010

1111
const cli = meow(
1212
`

index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import {Transform} from 'node:stream';
22
import pump from 'pump';
33
import abstractTransport, {type OnUnknown} from 'pino-abstract-transport';
44
import type {SonicBoom, SonicBoomOpts} from 'sonic-boom';
5-
import prettify from './lib/prettify.js';
6-
import buildSafeSonicBoom from './lib/build-safe-sonic-boom.js';
7-
import type {PrettifyOptions} from './lib/utils/types.js';
5+
import prettify from './lib/prettify.ts';
6+
import buildSafeSonicBoom from './lib/build-safe-sonic-boom.ts';
7+
import type {PrettifyOptions} from './lib/utils/types.ts';
88

99
function build(
1010
options: PrettifyOptions &

lib/formatters.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import pcStringify from 'json-stringify-pretty-compact';
1111
import {format} from 'date-fns';
1212
import getValue from 'get-value';
1313
import isUnicodeSupported from 'is-unicode-supported';
14-
import type {NumLevels, Levels, Colors} from './utils/types.js';
15-
import isObject from './utils/is-object.js';
14+
import type {NumLevels, Levels, Colors} from './utils/types.ts';
15+
import isObject from './utils/is-object.ts';
1616

1717
const nl = '\n';
1818

@@ -21,10 +21,9 @@ const defaultTimeFormat = 'h:mm:ss.SSS aaa';
2121
/** key map cache - assigned once at startup if user has custom keymap */
2222
const highlight = _highlight.default;
2323

24-
const colorMap: Record<Levels | 'userlvl', Colors> = {
24+
const colorMap: Record<Levels, Colors> = {
2525
warn: 'yellow',
2626
info: 'cyan',
27-
userlvl: 'cyan',
2827
error: 'red',
2928
debug: 'blue',
3029
trace: 'white',

lib/prettify.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import {logLineFactory} from 'json-log-line';
44
import _highlight from 'cli-highlight';
5-
import type {PrettifyOptions} from './utils/types.js';
6-
import {Formatter} from './formatters.js';
5+
import type {PrettifyOptions} from './utils/types.ts';
6+
import {Formatter} from './formatters.ts';
77

88
const defaultTimeFormat = 'h:mm:ss.SSS aaa';
99

lib/utils/convert-log-number.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {Levels} from './types.js';
1+
import type {Levels} from './types.ts';
22

33
function convertLogNumber(level: number): Levels | 'userlvl' {
44
if (level === 10) return 'trace';

lib/utils/is-empty.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import isObject from './is-object.js';
1+
import isObject from './is-object.ts';
22

33
function isEmpty(object: unknown): boolean {
44
return Boolean(
55
isObject(object) &&
6-
(object === undefined ||
7-
object === null ||
8-
Object.keys(object).length === 0),
6+
(object === undefined ||
7+
object === null ||
8+
Object.keys(object).length === 0),
99
);
1010
}
1111

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
"prepare": "husky",
5454
"release": "np",
5555
"test": "npm run build:test && c8 ava",
56+
"test:all": "npm run test && npm run test:node",
57+
"test:node": "npm run build:test && node --test --test-update-snapshots test-node/**/*.test.ts",
5658
"test:watch": "ava --watch",
5759
"update": "ncu -i"
5860
},

test-node/cli.test.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/* eslint-disable @typescript-eslint/no-floating-promises */
2+
import {test, type TestContext} from 'node:test';
3+
import {format} from 'date-fns';
4+
import {execa} from 'execa';
5+
import {err} from 'pino-std-serializers';
6+
7+
test('cli --help runs without error', async (t: TestContext) => {
8+
const {stdout} = await execa('node', ['dist/cli.js', '--help']);
9+
t.assert.snapshot(stdout);
10+
});
11+
12+
test('cli formats a log line', async (t: TestContext) => {
13+
const {stdout} = await execa('node', ['dist/cli.js', '--colors=false'], {
14+
input: JSON.stringify({
15+
level: 30,
16+
msg: 'hello',
17+
time: Date.now(),
18+
}),
19+
});
20+
console.log(stdout);
21+
t.assert.ok(stdout.includes('INFO hello'));
22+
});
23+
24+
test('cli respects --messageKey option', async (t: TestContext) => {
25+
const time = Date.now();
26+
// Test with default messageKey
27+
const {stdout: stdoutWithDefaultMessageKey} = await execa(
28+
'node',
29+
['dist/cli.js'],
30+
{
31+
input: JSON.stringify({
32+
level: 30,
33+
msg: 'hello',
34+
time,
35+
}),
36+
},
37+
);
38+
39+
const {stdout} = await execa(
40+
'node',
41+
['dist/cli.js', '--messageKey=message'],
42+
{
43+
input: JSON.stringify({
44+
level: 30,
45+
message: 'hello',
46+
time,
47+
}),
48+
},
49+
);
50+
51+
t.assert.ok(stdoutWithDefaultMessageKey.includes('INFO hello'));
52+
t.assert.ok(stdout.includes('INFO hello'));
53+
t.assert.strictEqual(stdoutWithDefaultMessageKey, stdout);
54+
});
55+
56+
test('cli respects --errorKey option', async (t: TestContext) => {
57+
const serializedError = err(new Error('test error'));
58+
const time = Date.now();
59+
60+
const {stdout: stdoutWithDefaultErrorKey} = await execa(
61+
'node',
62+
['dist/cli.js'],
63+
{
64+
input: JSON.stringify({
65+
level: 50,
66+
err: serializedError,
67+
time,
68+
}),
69+
},
70+
);
71+
72+
const {stdout: stdOutWithErrorKeyOption} = await execa(
73+
'node',
74+
['dist/cli.js', '--errorKey=error'],
75+
{
76+
input: JSON.stringify({
77+
level: 50,
78+
error: serializedError,
79+
time,
80+
}),
81+
},
82+
);
83+
t.assert.strictEqual(stdoutWithDefaultErrorKey, stdOutWithErrorKeyOption);
84+
});
85+
86+
test('cli respects --timeKey option', async (t: TestContext) => {
87+
const time = Date.now();
88+
89+
const {stdout: stdOutWithDefaultTimeKey} = await execa(
90+
'node',
91+
['dist/cli.js'],
92+
{
93+
input: JSON.stringify({
94+
level: 30,
95+
time,
96+
}),
97+
},
98+
);
99+
100+
const {stdout: stdoutWithTimeKeyOption} = await execa(
101+
'node',
102+
['dist/cli.js', '--timeKey=timestamp'],
103+
{
104+
input: JSON.stringify({
105+
level: 30,
106+
timestamp: time,
107+
}),
108+
},
109+
);
110+
t.assert.strictEqual(stdoutWithTimeKeyOption, stdOutWithDefaultTimeKey);
111+
});
112+
113+
// test cli timeformat option
114+
test('cli respects --timeFormat option', async (t: TestContext) => {
115+
const time = Date.now();
116+
const {stdout} = await execa(
117+
'node',
118+
['dist/cli.js', '--timeFormat=yyyy-MM-dd HH:mm:ss'],
119+
{
120+
input: JSON.stringify({
121+
level: 30,
122+
msg: 'hello',
123+
time,
124+
}),
125+
},
126+
);
127+
128+
// Check if the output contains the formatted time
129+
t.assert.ok(stdout.includes(format(time, 'yyyy-MM-dd HH:mm:ss')));
130+
});
131+
132+
// test cli singleLine option
133+
test('cli respects --singleLine option', async (t: TestContext) => {
134+
const input = JSON.stringify({
135+
level: 30,
136+
msg: 'hello',
137+
time: Date.now(),
138+
extra: {
139+
field1: 'value1',
140+
field2: 'value2',
141+
field3: 'value3',
142+
field4: 'value4',
143+
field5: 'value5',
144+
},
145+
});
146+
147+
const {stdout: stdoutMultiline} = await execa('node', ['dist/cli.js'], {
148+
input,
149+
});
150+
151+
const {stdout} = await execa('node', ['dist/cli.js', '--singleLine'], {
152+
input,
153+
});
154+
155+
t.assert.ok(stdoutMultiline.includes('\n'));
156+
// Check if the output is a single line
157+
t.assert.ok(!stdout.includes('\n'));
158+
});

test-node/cli.test.ts.snapshot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
exports[`cli --help runs without error 1`] = `
2+
"\\n Prettiest Pino Prettifier in all the land\\n\\n Usage\\n $ node my-app-with-pino-logging | pino-princess\\n\\n Options\\n --exclude, -e excluded log fields separated by comma. Is overriden by included fields.\\n --include, -i included log fields separated by comma. Overrides excluded fields.\\n --messageKey key for the message field, defaults to 'msg'\\n --errorKey key for the error field, defaults to 'err'\\n --timeKey key for the time field, defaults to 'time'\\n --timeFormat format for the time field, passed to date-fns format defaults to 'h:mm:ss.SSS aaa'\\n --singleLine format the output as a single line, defaults to false\\n --unicode force unicode emojis on or off, auto-detected by default\\n --no-colors disable all color output, auto-detected by default\\n \\n"
3+
`;

test-node/formatters.test.ts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/* eslint-disable @typescript-eslint/no-floating-promises */
2+
import {test, before} from 'node:test';
3+
import assert from 'node:assert';
4+
import {Formatter} from '../lib/formatters.ts';
5+
6+
let stripAnsi: (str: string) => string;
7+
8+
before(async () => {
9+
const {default: stripAnsiModule} = await import('strip-ansi');
10+
stripAnsi = stripAnsiModule;
11+
});
12+
13+
const {
14+
formatLevel,
15+
formatLoadTime,
16+
formatName,
17+
formatMessage,
18+
formatExtraFields,
19+
formatMethod,
20+
formatStack,
21+
formatUrl,
22+
formatStatusCode,
23+
formatErrorProp,
24+
formatId,
25+
} = new Formatter({
26+
keyMap: {},
27+
supportsColor: true,
28+
supportsUnicode: true,
29+
});
30+
31+
test('formatLevel', () => {
32+
/**
33+
* note: the space after some of the levels is intentional
34+
* as it is part of the formatLevel function, which pads the shorter strings
35+
*/
36+
37+
const info = stripAnsi(formatLevel(30));
38+
assert.strictEqual(info, '✨ INFO ');
39+
40+
const warn = stripAnsi(formatLevel(40));
41+
assert.strictEqual(warn, '⚠️ WARN ');
42+
43+
const error = stripAnsi(formatLevel(50));
44+
assert.strictEqual(error, '🚨 ERROR');
45+
46+
const fatal = stripAnsi(formatLevel(60));
47+
assert.strictEqual(fatal, '💀 FATAL');
48+
49+
// const userlvl = stripAnsi(formatLevel(0));
50+
// assert.strictEqual(userlvl, '👤 USERLVL');
51+
52+
const debug = stripAnsi(formatLevel(20));
53+
assert.strictEqual(debug, '🐛 DEBUG');
54+
});
55+
56+
test('formatLoadTime', () => {
57+
const loadTime1 = stripAnsi(formatLoadTime('0.1') ?? '');
58+
assert.strictEqual(loadTime1, '0ms');
59+
60+
const loadTime2 = stripAnsi(formatLoadTime('100') ?? '');
61+
assert.strictEqual(loadTime2, '100ms');
62+
63+
const loadTime3 = stripAnsi(formatLoadTime(500) ?? '');
64+
assert.strictEqual(loadTime3, '500ms');
65+
});
66+
67+
test('formatName', () => {
68+
const name1 = stripAnsi(formatName('name') ?? '');
69+
assert.strictEqual(name1, '[name]');
70+
});
71+
72+
test('formatMessage', () => {
73+
const messageInfo = stripAnsi(formatMessage('message', {level: 30}) ?? '');
74+
assert.strictEqual(messageInfo, 'message');
75+
76+
const messageWarn = stripAnsi(formatMessage('message', {level: 40}) ?? '');
77+
assert.strictEqual(messageWarn, 'message');
78+
79+
const messageError = stripAnsi(formatMessage('message', {level: 50}) ?? '');
80+
assert.strictEqual(messageError, 'message');
81+
82+
const messageFatal = stripAnsi(formatMessage('message', {level: 60}) ?? '');
83+
assert.strictEqual(messageFatal, 'message');
84+
85+
const messageUserlvl = stripAnsi(formatMessage('message', {level: 30}) ?? '');
86+
87+
assert.strictEqual(messageUserlvl, 'message');
88+
89+
const messageDebug = stripAnsi(formatMessage('message', {level: 20}) ?? '');
90+
assert.strictEqual(messageDebug, 'message');
91+
});
92+
93+
test('formatExtraFields', () => {
94+
const extraFields = stripAnsi(
95+
formatExtraFields({
96+
extra: 'fields',
97+
}) ?? '',
98+
);
99+
assert.strictEqual(extraFields, '\n "extra": "fields"');
100+
});
101+
102+
test('formatMethod', () => {
103+
const method = stripAnsi(formatMethod('method') ?? '');
104+
assert.strictEqual(method, 'METHOD');
105+
});
106+
107+
test('formatStack', () => {
108+
const stackFormatted = stripAnsi(formatStack('stack') ?? '');
109+
assert.strictEqual(stackFormatted, '\n stack');
110+
});
111+
112+
test('formatUrl', () => {
113+
const url = stripAnsi(formatUrl('url') ?? '');
114+
assert.strictEqual(url, ' url');
115+
116+
// with status code
117+
const urlWithStatusCode = stripAnsi(
118+
formatUrl('url', {res: {statusCode: 200}}) ?? '',
119+
);
120+
121+
assert.strictEqual(urlWithStatusCode, 'url');
122+
});
123+
124+
test('formatStatusCode', () => {
125+
const statusCode = stripAnsi(formatStatusCode(200) ?? '');
126+
assert.strictEqual(statusCode, '200');
127+
});
128+
129+
test('formatId', () => {
130+
const statusCode = stripAnsi(formatId('12345') ?? '');
131+
assert.strictEqual(statusCode, '[ID:12345]');
132+
});
133+
134+
test('formatErrorProp > basic error', () => {
135+
const error = new Error('test error');
136+
137+
const errorProp = stripAnsi(
138+
formatErrorProp({
139+
type: 'Error',
140+
message: 'test error',
141+
stack: error.stack,
142+
}) ?? '',
143+
);
144+
145+
assert.strictEqual(errorProp, `\n ${error.stack ?? ''}\n`);
146+
});

0 commit comments

Comments
 (0)