@meadown/logger 1.8.6 → 1.8.8
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/README.md +85 -35
- package/dist/caller/getCaller.js +3 -3
- package/dist/cjs/caller/getCaller.js +3 -3
- package/dist/cjs/constants.d.ts +1 -1
- package/dist/cjs/constants.js +1 -1
- package/dist/cjs/core/writeLog.js +7 -10
- package/dist/cjs/tap/tapAsync.js +9 -24
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/writeLog.js +7 -10
- package/dist/tap/tapAsync.js +9 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# @meadown/logger
|
|
4
4
|
|
|
5
|
-
A **development-focused logger** for Node.js and TypeScript
|
|
5
|
+
A **development-focused logger** for Node.js and TypeScript. Built to make your
|
|
6
6
|
development loop faster and your terminal actually readable.
|
|
7
7
|
|
|
8
8
|
No dependencies. No config. Import it and you're done.
|
|
@@ -10,7 +10,7 @@ No dependencies. No config. Import it and you're done.
|
|
|
10
10
|
## Why this exists
|
|
11
11
|
|
|
12
12
|
I kept writing the same `console.log` wrapper in every project. Every time.
|
|
13
|
-
Copy, paste, rename. And I still shipped it to production by accident.
|
|
13
|
+
Copy, paste, rename. And I still shipped it to production by accident. Unconsciously I
|
|
14
14
|
still spent ten minutes staring at logs trying to figure out which file they
|
|
15
15
|
came from.
|
|
16
16
|
|
|
@@ -19,6 +19,10 @@ At some point I just built the thing I always wanted.
|
|
|
19
19
|
One import. No config. No dependencies. It shows you exactly where every log
|
|
20
20
|
came from, and it gets out of the way when you ship.
|
|
21
21
|
|
|
22
|
+
It's not trying to be Winston or Pino. No transports, no log levels, no config files.
|
|
23
|
+
Just a better `console.log` for the hours you spend in development. One that
|
|
24
|
+
tells you where things came from and disappears when you ship.
|
|
25
|
+
|
|
22
26
|
> The full story — the problem, the research, every design decision, and
|
|
23
27
|
> everything that got cut — is in [`docs/STORY.md`](docs/STORY.md).
|
|
24
28
|
|
|
@@ -27,7 +31,7 @@ came from, and it gets out of the way when you ship.
|
|
|
27
31
|
- **Zero dependencies**
|
|
28
32
|
- **Development-focused** — built for the dev experience, not production ops
|
|
29
33
|
- **Clickable source link** — every log is a clickable link to the exact file it came from
|
|
30
|
-
- **
|
|
34
|
+
- **Tap logging** — log any value or promise inline; fetch calls also get timing, status, size, and body
|
|
31
35
|
- **Color-coded levels** — `[INFO]` cyan, `[WARN]` yellow, `[ERROR]` red
|
|
32
36
|
- **Tree layout output** — clean, scannable structure in your terminal
|
|
33
37
|
- **Collapsible messages** — cap long output with `logger.maxLines`
|
|
@@ -44,6 +48,9 @@ yarn add @meadown/logger
|
|
|
44
48
|
|
|
45
49
|
## Using it
|
|
46
50
|
|
|
51
|
+
Set `NODE_ENV=production` and all output is suppressed. Anything else and
|
|
52
|
+
logging is on. No config files, no init call, no options object.
|
|
53
|
+
|
|
47
54
|
```ts
|
|
48
55
|
import logger from "@meadown/logger"
|
|
49
56
|
|
|
@@ -60,9 +67,41 @@ logger.error("Something went wrong")
|
|
|
60
67
|
└── 05-30 04:00:00 PM - (server.ts:42)
|
|
61
68
|
```
|
|
62
69
|
|
|
70
|
+
### Recommended: single shared import
|
|
71
|
+
|
|
72
|
+
Rather than importing directly from `@meadown/logger` in every file, create
|
|
73
|
+
one shared module in your project and re-export from there. This gives you a
|
|
74
|
+
single place to set options like `maxLines` and keeps any future changes to
|
|
75
|
+
one file.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// lib/logger.ts
|
|
79
|
+
import logger from "@meadown/logger"
|
|
80
|
+
|
|
81
|
+
logger.maxLines = 10 // configure once, applies everywhere
|
|
82
|
+
|
|
83
|
+
export default logger
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
// anywhere else in your project
|
|
88
|
+
import logger from "@/lib/logger"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
When re-exporting, use a direct re-export, Not a wrapper function. A wrapper
|
|
92
|
+
breaks the caller location shown in every log line.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// GOOD — location stays honest
|
|
96
|
+
export { default as logger } from "@meadown/logger"
|
|
97
|
+
|
|
98
|
+
// BAD — every log points at this file, not the real caller
|
|
99
|
+
export const logger = (...args) => log(...args)
|
|
100
|
+
```
|
|
101
|
+
|
|
63
102
|
## API response logging
|
|
64
103
|
|
|
65
|
-
Drop `tap` into any `await` chain
|
|
104
|
+
Drop `tap` into any `await` chain. You get timing, status, size, and the
|
|
66
105
|
actual response body. The promise flows through untouched. One line of code.
|
|
67
106
|
|
|
68
107
|
```ts
|
|
@@ -93,25 +132,45 @@ const user = await logger.tap(
|
|
|
93
132
|
You can immediately see: was it successful? How long did it take? What came
|
|
94
133
|
back? Without opening DevTools.
|
|
95
134
|
|
|
96
|
-

|
|
136
|
+
|
|
137
|
+
### Tap any value
|
|
138
|
+
|
|
139
|
+
`tap` works on anything, not just fetch. Pass in any value or expression and
|
|
140
|
+
get it back exactly as it was. The only thing that happens is a log.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
// numbers, strings, objects — logged and returned as-is
|
|
144
|
+
logger.tap(port, "port")
|
|
145
|
+
logger.tap(process.env.NODE_ENV, "env")
|
|
146
|
+
logger.tap(config, "loaded config")
|
|
147
|
+
```
|
|
97
148
|
|
|
98
|
-
|
|
149
|
+
```ts
|
|
150
|
+
// async functions — promise flows through, timing logged when it settles
|
|
151
|
+
const user = await logger.tap(getUser(), "getUser")
|
|
152
|
+
const config = await logger.tap(loadConfig(), "loadConfig")
|
|
153
|
+
```
|
|
99
154
|
|
|
100
155
|
```ts
|
|
101
|
-
|
|
102
|
-
|
|
156
|
+
// inline — no temp variable needed
|
|
157
|
+
server.listen(logger.tap(port, "port"))
|
|
103
158
|
```
|
|
104
159
|
|
|
160
|
+
If it's a promise, `tap` logs elapsed time once it settles. If it resolves
|
|
161
|
+
to a `Response` (any fetch like call), you also get status and size, same
|
|
162
|
+
as the fetch example above.
|
|
163
|
+
|
|
105
164
|
## Clickable source link
|
|
106
165
|
|
|
107
|
-
That `(server.ts:42)` is a **clickable link
|
|
108
|
-
line
|
|
109
|
-
Terminal. Degrades to plain text everywhere else.
|
|
166
|
+
That `(server.ts:42)` is a **clickable link**. Click it and the file opens.
|
|
167
|
+
The line number is right there so you can jump straight to it. Works in VS Code,
|
|
168
|
+
iTerm2, WezTerm, Kitty, and Windows Terminal. Degrades to plain text everywhere else.
|
|
110
169
|
|
|
111
170
|
## Color-coded levels
|
|
112
171
|
|
|
113
|
-
`[INFO]` cyan · `[WARN]` yellow · `[ERROR]` red. Timestamp and location tinted teal.
|
|
114
|
-
Auto-disabled when output is piped
|
|
172
|
+
`[INFO]` , `[TAP]` cyan · `[WARN]` yellow · `[ERROR]` red. Timestamp and location tinted teal.
|
|
173
|
+
Auto-disabled when output is piped no escape codes in your log files.
|
|
115
174
|
|
|
116
175
|
## Tree layout output
|
|
117
176
|
|
|
@@ -121,7 +180,7 @@ Auto-disabled when output is piped — no escape codes in your log files.
|
|
|
121
180
|
└── 05-30 04:00:00 PM - (server.ts:42)
|
|
122
181
|
```
|
|
123
182
|
|
|
124
|
-
Level tag, message, timestamp, and location
|
|
183
|
+
Level tag, message, timestamp, and location all in a clean tree. Easy to scan,
|
|
125
184
|
even in a busy terminal.
|
|
126
185
|
|
|
127
186
|
## Collapsible messages
|
|
@@ -131,34 +190,25 @@ logger.maxLines = 5 // show 5 lines, then "... N more lines"
|
|
|
131
190
|
logger.maxLines = 0 // default — show everything
|
|
132
191
|
```
|
|
133
192
|
|
|
134
|
-
### One thing if you re-export it
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
// GOOD — location stays honest
|
|
138
|
-
export { default as logger } from "@meadown/logger"
|
|
139
|
-
|
|
140
|
-
// BAD — every log points at this file, not the real caller
|
|
141
|
-
export const logger = (...args) => log(...args)
|
|
142
|
-
```
|
|
143
|
-
|
|
144
193
|
## NODE_ENV
|
|
145
194
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
195
|
+
You shouldn't have to think about whether your logs will leak into production.
|
|
196
|
+
This package reads `NODE_ENV` and handles it for you. Set it to `production`
|
|
197
|
+
and all output is handled for you. You never have to remember to wrap a log call,
|
|
198
|
+
remove a debug line, or grep the codebase before a release.
|
|
150
199
|
|
|
151
|
-
| `NODE_ENV` | Logs?
|
|
152
|
-
| ---------------------------------------- |
|
|
153
|
-
| not set, `development`, or anything else | shown
|
|
154
|
-
| `production` |
|
|
200
|
+
| `NODE_ENV` | Logs? |
|
|
201
|
+
| ---------------------------------------- | ---------- |
|
|
202
|
+
| not set, `development`, or anything else | shown |
|
|
203
|
+
| `production` | suppressed |
|
|
155
204
|
|
|
156
205
|
## Security
|
|
157
206
|
|
|
158
207
|
Zero dependencies, no file or network access, nothing persisted.
|
|
159
|
-
See [SECURITY.md](https://github.com/meadown/meadown-logger/blob/main/SECURITY.md)
|
|
160
|
-
for the full security model.
|
|
208
|
+
See [SECURITY.md](https://github.com/meadown/meadown-logger/blob/main/SECURITY.md) for the full security model.
|
|
161
209
|
|
|
162
210
|
## License
|
|
163
211
|
|
|
164
|
-
|
|
212
|
+
Architected and developed by [Dewan Mobashirul](https://linkedin.com/in/dewan-meadown)
|
|
213
|
+
|
|
214
|
+
MIT © [meadown](https://github.com/meadown)
|
package/dist/caller/getCaller.js
CHANGED
|
@@ -23,10 +23,10 @@ export default function getCaller() {
|
|
|
23
23
|
// Split off the trailing `:line:column`, keeping the (possibly colon-bearing)
|
|
24
24
|
// path intact (e.g. Windows `C:\…` or `file://…`).
|
|
25
25
|
const match = inner.match(/^(.*):(\d+):\d+$/);
|
|
26
|
-
|
|
27
|
-
if (file === undefined)
|
|
26
|
+
if (match === null)
|
|
28
27
|
return UNKNOWN;
|
|
29
|
-
const
|
|
28
|
+
const file = match[1] ?? "";
|
|
29
|
+
const line = Number(match[2]);
|
|
30
30
|
const base = file.split(/[/\\]/).pop() ?? "";
|
|
31
31
|
if (!SOURCE_FILE.test(base))
|
|
32
32
|
return UNKNOWN;
|
|
@@ -26,10 +26,10 @@ function getCaller() {
|
|
|
26
26
|
// Split off the trailing `:line:column`, keeping the (possibly colon-bearing)
|
|
27
27
|
// path intact (e.g. Windows `C:\…` or `file://…`).
|
|
28
28
|
const match = inner.match(/^(.*):(\d+):\d+$/);
|
|
29
|
-
|
|
30
|
-
if (file === undefined)
|
|
29
|
+
if (match === null)
|
|
31
30
|
return UNKNOWN;
|
|
32
|
-
const
|
|
31
|
+
const file = match[1] ?? "";
|
|
32
|
+
const line = Number(match[2]);
|
|
33
33
|
const base = file.split(/[/\\]/).pop() ?? "";
|
|
34
34
|
if (!SOURCE_FILE.test(base))
|
|
35
35
|
return UNKNOWN;
|
package/dist/cjs/constants.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export declare const BRANCH_END = "\u2514\u2500\u2500";
|
|
|
9
9
|
export declare const SEPARATOR = "-";
|
|
10
10
|
/** Hang-indent for message continuation lines, so they align under the message
|
|
11
11
|
* text (the `├── ` branch is 4 columns wide). */
|
|
12
|
-
export declare const MESSAGE_INDENT = "
|
|
12
|
+
export declare const MESSAGE_INDENT = "\u2502 ";
|
|
13
13
|
/** Default for the collapse setting: 0 = show every line. */
|
|
14
14
|
export declare const DEFAULT_MAX_LINES = 0;
|
package/dist/cjs/constants.js
CHANGED
|
@@ -22,6 +22,6 @@ exports.BRANCH_END = "└──"; // the last (metadata) branch
|
|
|
22
22
|
exports.SEPARATOR = "-"; // between the timestamp and the location
|
|
23
23
|
/** Hang-indent for message continuation lines, so they align under the message
|
|
24
24
|
* text (the `├── ` branch is 4 columns wide). */
|
|
25
|
-
exports.MESSAGE_INDENT = "
|
|
25
|
+
exports.MESSAGE_INDENT = "│ ";
|
|
26
26
|
/** Default for the collapse setting: 0 = show every line. */
|
|
27
27
|
exports.DEFAULT_MAX_LINES = 0;
|
|
@@ -76,17 +76,14 @@ function writeLog(opts) {
|
|
|
76
76
|
// One terminal check drives both color and clickable links — `isTTY` is the
|
|
77
77
|
// single source of truth (DRY). Off when output is piped/redirected.
|
|
78
78
|
const useColor = (0, isTTY_js_1.isTTY)(streamName);
|
|
79
|
+
const paint = (s, c) => useColor ? (0, color_js_1.colorize)(s, c) : s;
|
|
79
80
|
const location = formatLocation(caller, useColor);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
: `(${location})`;
|
|
87
|
-
const connector = useColor ? (0, color_js_1.colorize)(constants_js_1.BRANCH, "gray") : constants_js_1.BRANCH;
|
|
88
|
-
const connectorBottom = useColor ? (0, color_js_1.colorize)(constants_js_1.BRANCH_END, "gray") : constants_js_1.BRANCH_END;
|
|
89
|
-
const separator = useColor ? (0, color_js_1.colorize)(constants_js_1.SEPARATOR, "gray") : constants_js_1.SEPARATOR;
|
|
81
|
+
const tagOut = paint(tag, constants_js_1.TAG_COLOR[channel]);
|
|
82
|
+
const timeStamp = paint((0, getTimeStamp_js_1.default)(), "teal");
|
|
83
|
+
const locOut = paint(`(${location})`, "dimTeal");
|
|
84
|
+
const connector = paint(constants_js_1.BRANCH, "gray");
|
|
85
|
+
const connectorBottom = paint(constants_js_1.BRANCH_END, "gray");
|
|
86
|
+
const separator = paint(constants_js_1.SEPARATOR, "gray");
|
|
90
87
|
// Layout: the tag, the message hanging off a `├──` branch, then the timestamp
|
|
91
88
|
// and location on a `└──` branch below. Leading `\n` spaces entries apart.
|
|
92
89
|
const message = renderMessage(args, useColor);
|
package/dist/cjs/tap/tapAsync.js
CHANGED
|
@@ -106,23 +106,18 @@ async function readBody(res) {
|
|
|
106
106
|
* │ └── name: Leanne Graham
|
|
107
107
|
*/
|
|
108
108
|
function buildBlock(label, ms, res, body, useColor) {
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
const
|
|
109
|
+
const paint = (s, c) => useColor ? (0, color_js_1.colorize)(s, c) : s;
|
|
110
|
+
const pipe = paint("│", "gray");
|
|
111
|
+
const branch = paint("├──", "gray");
|
|
112
|
+
const last = paint("└──", "gray");
|
|
112
113
|
const indent = `${pipe} `;
|
|
113
|
-
const statusLine = `${indent}${branch} status: ${formatStatus(res, useColor)}`;
|
|
114
114
|
const timeLine = `${indent}${branch} time: ${formatDuration(ms, useColor)}`;
|
|
115
|
+
const statusLine = `${indent}${branch} status: ${formatStatus(res, useColor)}`;
|
|
115
116
|
const sizeLine = `${indent}${last} size: ${body.size}`;
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
`${indent}response:`,
|
|
119
|
-
timeLine,
|
|
120
|
-
statusLine,
|
|
121
|
-
sizeLine,
|
|
122
|
-
].join("\n");
|
|
117
|
+
const responseLines = [`${pipe}`, `${indent}response:`, timeLine, statusLine, sizeLine];
|
|
118
|
+
const head = label === undefined ? "" : `${label}\n`;
|
|
123
119
|
if (body.data === undefined) {
|
|
124
|
-
|
|
125
|
-
return [`${head}${responseBlock}`];
|
|
120
|
+
return [`${head}${responseLines.join("\n")}`];
|
|
126
121
|
}
|
|
127
122
|
// Render the body using util.formatWithOptions so objects/arrays look like
|
|
128
123
|
// console.log output — colors, proper nesting, no JSON.stringify quirkiness.
|
|
@@ -132,17 +127,7 @@ function buildBlock(label, ms, res, body, useColor) {
|
|
|
132
127
|
const bodyBlock = bodyLines
|
|
133
128
|
.map((line, i) => `${indent}${i === lastIdx ? last : branch} ${line}`)
|
|
134
129
|
.join("\n");
|
|
135
|
-
const full = [
|
|
136
|
-
`${pipe}`,
|
|
137
|
-
`${indent}response:`,
|
|
138
|
-
timeLine,
|
|
139
|
-
statusLine,
|
|
140
|
-
sizeLine,
|
|
141
|
-
`${pipe}`,
|
|
142
|
-
`${indent}body:`,
|
|
143
|
-
bodyBlock,
|
|
144
|
-
].join("\n");
|
|
145
|
-
const head = label === undefined ? "" : `${label}\n`;
|
|
130
|
+
const full = [...responseLines, `${pipe}`, `${indent}body:`, bodyBlock].join("\n");
|
|
146
131
|
return [`${head}${full}`];
|
|
147
132
|
}
|
|
148
133
|
/**
|
package/dist/constants.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export declare const BRANCH_END = "\u2514\u2500\u2500";
|
|
|
9
9
|
export declare const SEPARATOR = "-";
|
|
10
10
|
/** Hang-indent for message continuation lines, so they align under the message
|
|
11
11
|
* text (the `├── ` branch is 4 columns wide). */
|
|
12
|
-
export declare const MESSAGE_INDENT = "
|
|
12
|
+
export declare const MESSAGE_INDENT = "\u2502 ";
|
|
13
13
|
/** Default for the collapse setting: 0 = show every line. */
|
|
14
14
|
export declare const DEFAULT_MAX_LINES = 0;
|
package/dist/constants.js
CHANGED
|
@@ -19,6 +19,6 @@ export const BRANCH_END = "└──"; // the last (metadata) branch
|
|
|
19
19
|
export const SEPARATOR = "-"; // between the timestamp and the location
|
|
20
20
|
/** Hang-indent for message continuation lines, so they align under the message
|
|
21
21
|
* text (the `├── ` branch is 4 columns wide). */
|
|
22
|
-
export const MESSAGE_INDENT = "
|
|
22
|
+
export const MESSAGE_INDENT = "│ ";
|
|
23
23
|
/** Default for the collapse setting: 0 = show every line. */
|
|
24
24
|
export const DEFAULT_MAX_LINES = 0;
|
package/dist/core/writeLog.js
CHANGED
|
@@ -68,17 +68,14 @@ export function writeLog(opts) {
|
|
|
68
68
|
// One terminal check drives both color and clickable links — `isTTY` is the
|
|
69
69
|
// single source of truth (DRY). Off when output is piped/redirected.
|
|
70
70
|
const useColor = isTTY(streamName);
|
|
71
|
+
const paint = (s, c) => useColor ? colorize(s, c) : s;
|
|
71
72
|
const location = formatLocation(caller, useColor);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
: `(${location})`;
|
|
79
|
-
const connector = useColor ? colorize(BRANCH, "gray") : BRANCH;
|
|
80
|
-
const connectorBottom = useColor ? colorize(BRANCH_END, "gray") : BRANCH_END;
|
|
81
|
-
const separator = useColor ? colorize(SEPARATOR, "gray") : SEPARATOR;
|
|
73
|
+
const tagOut = paint(tag, TAG_COLOR[channel]);
|
|
74
|
+
const timeStamp = paint(getTimeStamp(), "teal");
|
|
75
|
+
const locOut = paint(`(${location})`, "dimTeal");
|
|
76
|
+
const connector = paint(BRANCH, "gray");
|
|
77
|
+
const connectorBottom = paint(BRANCH_END, "gray");
|
|
78
|
+
const separator = paint(SEPARATOR, "gray");
|
|
82
79
|
// Layout: the tag, the message hanging off a `├──` branch, then the timestamp
|
|
83
80
|
// and location on a `└──` branch below. Leading `\n` spaces entries apart.
|
|
84
81
|
const message = renderMessage(args, useColor);
|
package/dist/tap/tapAsync.js
CHANGED
|
@@ -102,23 +102,18 @@ async function readBody(res) {
|
|
|
102
102
|
* │ └── name: Leanne Graham
|
|
103
103
|
*/
|
|
104
104
|
function buildBlock(label, ms, res, body, useColor) {
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
const
|
|
105
|
+
const paint = (s, c) => useColor ? colorize(s, c) : s;
|
|
106
|
+
const pipe = paint("│", "gray");
|
|
107
|
+
const branch = paint("├──", "gray");
|
|
108
|
+
const last = paint("└──", "gray");
|
|
108
109
|
const indent = `${pipe} `;
|
|
109
|
-
const statusLine = `${indent}${branch} status: ${formatStatus(res, useColor)}`;
|
|
110
110
|
const timeLine = `${indent}${branch} time: ${formatDuration(ms, useColor)}`;
|
|
111
|
+
const statusLine = `${indent}${branch} status: ${formatStatus(res, useColor)}`;
|
|
111
112
|
const sizeLine = `${indent}${last} size: ${body.size}`;
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
`${indent}response:`,
|
|
115
|
-
timeLine,
|
|
116
|
-
statusLine,
|
|
117
|
-
sizeLine,
|
|
118
|
-
].join("\n");
|
|
113
|
+
const responseLines = [`${pipe}`, `${indent}response:`, timeLine, statusLine, sizeLine];
|
|
114
|
+
const head = label === undefined ? "" : `${label}\n`;
|
|
119
115
|
if (body.data === undefined) {
|
|
120
|
-
|
|
121
|
-
return [`${head}${responseBlock}`];
|
|
116
|
+
return [`${head}${responseLines.join("\n")}`];
|
|
122
117
|
}
|
|
123
118
|
// Render the body using util.formatWithOptions so objects/arrays look like
|
|
124
119
|
// console.log output — colors, proper nesting, no JSON.stringify quirkiness.
|
|
@@ -128,17 +123,7 @@ function buildBlock(label, ms, res, body, useColor) {
|
|
|
128
123
|
const bodyBlock = bodyLines
|
|
129
124
|
.map((line, i) => `${indent}${i === lastIdx ? last : branch} ${line}`)
|
|
130
125
|
.join("\n");
|
|
131
|
-
const full = [
|
|
132
|
-
`${pipe}`,
|
|
133
|
-
`${indent}response:`,
|
|
134
|
-
timeLine,
|
|
135
|
-
statusLine,
|
|
136
|
-
sizeLine,
|
|
137
|
-
`${pipe}`,
|
|
138
|
-
`${indent}body:`,
|
|
139
|
-
bodyBlock,
|
|
140
|
-
].join("\n");
|
|
141
|
-
const head = label === undefined ? "" : `${label}\n`;
|
|
126
|
+
const full = [...responseLines, `${pipe}`, `${indent}body:`, bodyBlock].join("\n");
|
|
142
127
|
return [`${head}${full}`];
|
|
143
128
|
}
|
|
144
129
|
/**
|
package/package.json
CHANGED