termpainter 2.0.0 → 2.0.1
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 +127 -72
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# termpainter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build clean, structured CLI output with zero dependencies.
|
|
4
|
+
|
|
5
|
+
termpainter gives you semantic styles, boxes, tables, spinners, layouts and more. works in Node 18+ and Bun. full TypeScript support.
|
|
4
6
|
```sh
|
|
5
7
|
npm install termpainter
|
|
6
8
|
```
|
|
@@ -9,6 +11,73 @@ npm install termpainter
|
|
|
9
11
|
|
|
10
12
|
---
|
|
11
13
|
|
|
14
|
+
## real world examples
|
|
15
|
+
|
|
16
|
+
### deploy pipeline
|
|
17
|
+
```ts
|
|
18
|
+
import { style, box, columns } from 'termpainter'
|
|
19
|
+
|
|
20
|
+
console.log(box(
|
|
21
|
+
style.group('Deploy', [
|
|
22
|
+
style.success('Dependencies installed'),
|
|
23
|
+
style.success('TypeScript compiled'),
|
|
24
|
+
style.success('22/22 tests passed'),
|
|
25
|
+
style.success('Bundle created (10.5 kB)'),
|
|
26
|
+
]),
|
|
27
|
+
{ color: 'green', title: 'CI/CD' }
|
|
28
|
+
))
|
|
29
|
+
|
|
30
|
+
console.log(columns(
|
|
31
|
+
style.group('Services', [
|
|
32
|
+
style.success('API'),
|
|
33
|
+
style.success('Auth'),
|
|
34
|
+
style.error('Database'),
|
|
35
|
+
style.warn('Cache'),
|
|
36
|
+
]),
|
|
37
|
+
style.group('Stats', [
|
|
38
|
+
style.info('Uptime: 3d 2h'),
|
|
39
|
+
style.info('Memory: 512 MB'),
|
|
40
|
+
style.warn('CPU: 87%'),
|
|
41
|
+
style.info('Port: 3000'),
|
|
42
|
+
])
|
|
43
|
+
))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
<img src="https://raw.githubusercontent.com/abd105/termpainter/main/assets/example-deploy.png" width="500" alt="deploy pipeline example" />
|
|
47
|
+
|
|
48
|
+
### structured logging
|
|
49
|
+
```ts
|
|
50
|
+
import { style } from 'termpainter'
|
|
51
|
+
|
|
52
|
+
style.success('User created', { id: 847, role: 'admin', plan: 'pro' })
|
|
53
|
+
style.error('Request failed', { status: 503, path: '/api/checkout', retries: 3 })
|
|
54
|
+
style.warn('Rate limit approaching', { limit: 1000, current: 847, reset: '60s' })
|
|
55
|
+
style.info('Deploy started', { env: 'production', version: 'v2.0.0', region: 'us-east-1' })
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
<img src="https://raw.githubusercontent.com/abd105/termpainter/main/assets/example-logs.png" width="400" alt="structured logging example" />
|
|
59
|
+
|
|
60
|
+
### CLI status dashboard
|
|
61
|
+
```ts
|
|
62
|
+
import { style, badge, columns } from 'termpainter'
|
|
63
|
+
|
|
64
|
+
console.log(columns(
|
|
65
|
+
style.table({ Status: 'Running', Uptime: '3d 2h', Memory: '512 MB', CPU: '12%' }),
|
|
66
|
+
style.table({ Region: 'us-east-1', Version: 'v2.0.0', Node: '22.x', Port: '3000' })
|
|
67
|
+
))
|
|
68
|
+
|
|
69
|
+
console.log(
|
|
70
|
+
badge('production', 'green') + ' ' +
|
|
71
|
+
badge('v2.0.0', 'cyan') + ' ' +
|
|
72
|
+
badge('0 deps', 'magenta') + ' ' +
|
|
73
|
+
badge('TypeScript', 'blue')
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
<img src="https://raw.githubusercontent.com/abd105/termpainter/main/assets/example-dashboard.png" width="500" alt="status dashboard example" />
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
12
81
|
## usage
|
|
13
82
|
```ts
|
|
14
83
|
import { style, badge, box, paint, spin, strip, columns, truncate,
|
|
@@ -30,14 +99,12 @@ style.highlight('termpainter') // cyan
|
|
|
30
99
|
|
|
31
100
|
### structured log output
|
|
32
101
|
|
|
33
|
-
any `style.*` method accepts an optional second argument
|
|
102
|
+
any `style.*` method accepts an optional second argument. a plain object whose keys and values are printed below the message, indented with keys in cyan.
|
|
34
103
|
```ts
|
|
35
104
|
style.info('User created', { id: 123, role: 'admin' })
|
|
36
105
|
// ℹ User created
|
|
37
106
|
// id 123
|
|
38
107
|
// role admin
|
|
39
|
-
|
|
40
|
-
style.error('Request failed', { status: 503, path: '/api/data' })
|
|
41
108
|
```
|
|
42
109
|
|
|
43
110
|
### debug
|
|
@@ -70,7 +137,7 @@ style.list(items, { bullet: '-', color: 'gray', indent: 2 })
|
|
|
70
137
|
|
|
71
138
|
inline labels. good for status, versions, environments.
|
|
72
139
|
```ts
|
|
73
|
-
badge('
|
|
140
|
+
badge('v2.0.0', 'cyan')
|
|
74
141
|
badge('PASS', 'green')
|
|
75
142
|
badge('FAIL', 'red')
|
|
76
143
|
badge('production', 'green')
|
|
@@ -79,13 +146,12 @@ badge('offline', 'red')
|
|
|
79
146
|
|
|
80
147
|
### boxes
|
|
81
148
|
|
|
82
|
-
draws a clean unicode border around anything. multiline works fine. fully composable
|
|
149
|
+
draws a clean unicode border around anything. multiline works fine. fully composable. supports an optional title in the top border.
|
|
83
150
|
```ts
|
|
84
151
|
box('Deploy complete\n3 services restarted\nAll checks passed', 'green')
|
|
85
152
|
box('Critical error\nProcess exited with code 1', 'red')
|
|
86
153
|
box(style.success('done')) // styled content inside a box
|
|
87
154
|
|
|
88
|
-
// with title
|
|
89
155
|
box('Deploy complete\n3 services restarted', { color: 'green', title: 'Deploy' })
|
|
90
156
|
// ╭ Deploy ──────────────────╮
|
|
91
157
|
// │ Deploy complete │
|
|
@@ -123,15 +189,6 @@ style.timestamp('Deploy complete', 'green') // timestamp in green
|
|
|
123
189
|
style.timestamp('Connection failed', 'red') // timestamp in red
|
|
124
190
|
```
|
|
125
191
|
|
|
126
|
-
### paint
|
|
127
|
-
|
|
128
|
-
low level, for when you need something the presets don't cover.
|
|
129
|
-
```ts
|
|
130
|
-
paint('custom text', { color: 'magenta', bold: true })
|
|
131
|
-
paint('highlighted', { color: 'white', bg: 'blue' })
|
|
132
|
-
paint('soft note', { color: 'gray', italic: true, dim: true })
|
|
133
|
-
```
|
|
134
|
-
|
|
135
192
|
### group
|
|
136
193
|
|
|
137
194
|
groups a list of already-styled lines under a labeled header.
|
|
@@ -152,34 +209,30 @@ renders two strings side by side, ANSI-aware. falls back to two lines in non-int
|
|
|
152
209
|
columns('Left content', 'Right content')
|
|
153
210
|
columns(style.success('Build passed'), style.info('Tests: 22/22'))
|
|
154
211
|
columns(badge('production', 'green'), badge('v2.0.0', 'cyan'))
|
|
155
|
-
|
|
156
212
|
columns(left, right, { width: 100, gap: 6 })
|
|
157
213
|
```
|
|
158
214
|
|
|
159
215
|
### truncate
|
|
160
216
|
|
|
161
|
-
truncates a string to a maximum visible length and appends
|
|
217
|
+
truncates a string to a maximum visible length and appends `...`. uses `strip()` internally so ANSI codes don't count toward the length.
|
|
162
218
|
```ts
|
|
163
219
|
truncate('very long string that overflows', 20)
|
|
164
|
-
// => 'very long string tha
|
|
220
|
+
// => 'very long string tha...'
|
|
165
221
|
|
|
166
222
|
truncate(style.success('Build complete'), 10)
|
|
167
|
-
// => truncated styled string with ANSI codes preserved
|
|
168
223
|
```
|
|
169
224
|
|
|
170
225
|
### spinner
|
|
171
226
|
|
|
172
|
-
animated terminal spinner. returns a handle with `succeed`, `fail`, and `update`. no external dependencies. automatically degrades to static
|
|
227
|
+
animated terminal spinner. returns a handle with `succeed`, `fail`, and `update`. no external dependencies. automatically degrades to static output when not in a TTY.
|
|
173
228
|
```ts
|
|
174
229
|
const s = spin('Deploying...')
|
|
175
230
|
|
|
176
|
-
s.update('Still working...')
|
|
231
|
+
s.update('Still working...')
|
|
177
232
|
s.update('Almost done...')
|
|
178
233
|
|
|
179
|
-
s.succeed('Deploy complete')
|
|
180
|
-
s.fail('Deploy failed')
|
|
181
|
-
|
|
182
|
-
s.succeed() // reuse current message
|
|
234
|
+
s.succeed('Deploy complete')
|
|
235
|
+
s.fail('Deploy failed')
|
|
183
236
|
```
|
|
184
237
|
|
|
185
238
|
### strip
|
|
@@ -192,71 +245,73 @@ const raw = strip(style.success('Build complete'))
|
|
|
192
245
|
fs.appendFileSync('app.log', strip(style.info('Server started')) + '\n')
|
|
193
246
|
```
|
|
194
247
|
|
|
195
|
-
###
|
|
248
|
+
### paint
|
|
196
249
|
|
|
197
|
-
|
|
250
|
+
low level, for when you need something the presets don't cover.
|
|
198
251
|
```ts
|
|
199
|
-
|
|
252
|
+
paint('custom text', { color: 'magenta', bold: true })
|
|
253
|
+
paint('highlighted', { color: 'white', bg: 'blue' })
|
|
254
|
+
paint('soft note', { color: 'gray', italic: true, dim: true })
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### themes
|
|
200
258
|
|
|
259
|
+
globally override colors and icons for all `style.*` methods. all keys are optional. call `resetTheme()` to restore defaults.
|
|
260
|
+
```ts
|
|
201
261
|
setTheme({
|
|
202
262
|
success: { color: 'cyan', icon: '✓' },
|
|
203
263
|
error: { color: 'magenta', icon: '✕' },
|
|
204
264
|
warn: { color: 'yellow' },
|
|
205
|
-
info: { color: 'blue', icon: '
|
|
206
|
-
debug: { color: 'gray', dim: true },
|
|
207
|
-
muted: { color: 'gray', dim: true },
|
|
208
|
-
highlight: { color: 'green' },
|
|
265
|
+
info: { color: 'blue', icon: '>' },
|
|
209
266
|
})
|
|
210
267
|
|
|
211
|
-
style.success('done')
|
|
212
|
-
style.error('oops')
|
|
268
|
+
style.success('done') // ✓ done (cyan, custom icon)
|
|
269
|
+
style.error('oops') // ✕ oops (magenta)
|
|
213
270
|
|
|
214
|
-
resetTheme()
|
|
271
|
+
resetTheme() // back to defaults
|
|
215
272
|
```
|
|
216
273
|
|
|
217
|
-
###
|
|
274
|
+
### custom icons
|
|
218
275
|
|
|
219
|
-
|
|
276
|
+
override the default icons for any or all style methods. unspecified keys fall back to defaults.
|
|
220
277
|
```ts
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
setTestMode(true)
|
|
224
|
-
|
|
225
|
-
style.timestamp('Server started') // => 'Server started' (no [HH:MM:SS])
|
|
226
|
-
const s = spin('Loading...') // prints once, no animation
|
|
227
|
-
s.succeed('Done') // prints style.success line
|
|
278
|
+
setIcons({ success: '✓', error: '✕' })
|
|
228
279
|
|
|
229
|
-
|
|
280
|
+
style.success('done') // ✓ done
|
|
281
|
+
style.warn('careful') // ⚠ careful (default unchanged)
|
|
230
282
|
```
|
|
231
283
|
|
|
284
|
+
available keys: `success`, `error`, `warn`, `info`, `debug`
|
|
285
|
+
|
|
232
286
|
### silent mode
|
|
233
287
|
|
|
234
288
|
suppress all output globally. every function returns an empty string and produces no side effects. useful for tests, CI, and benchmarks.
|
|
235
289
|
```ts
|
|
236
290
|
setSilent(true)
|
|
237
291
|
|
|
238
|
-
style.success('done')
|
|
239
|
-
badge('
|
|
240
|
-
box('hello')
|
|
292
|
+
style.success('done') // ''
|
|
293
|
+
badge('v2.0.0', 'cyan') // ''
|
|
294
|
+
box('hello') // ''
|
|
241
295
|
|
|
242
|
-
setSilent(false)
|
|
296
|
+
setSilent(false) // restore normal output
|
|
243
297
|
```
|
|
244
298
|
|
|
245
|
-
###
|
|
299
|
+
### test mode
|
|
246
300
|
|
|
247
|
-
|
|
301
|
+
makes output deterministic for snapshot testing. `style.timestamp()` omits the time prefix, `spin()` renders statically, `isInteractive()` returns `false`.
|
|
248
302
|
```ts
|
|
249
|
-
|
|
303
|
+
setTestMode(true)
|
|
250
304
|
|
|
251
|
-
style.
|
|
252
|
-
|
|
253
|
-
|
|
305
|
+
style.timestamp('Server started') // 'Server started' (no [HH:MM:SS])
|
|
306
|
+
const s = spin('Loading...') // prints once, no animation
|
|
307
|
+
s.succeed('Done')
|
|
254
308
|
|
|
255
|
-
|
|
309
|
+
setTestMode(false)
|
|
310
|
+
```
|
|
256
311
|
|
|
257
312
|
### isInteractive
|
|
258
313
|
|
|
259
|
-
returns `true` if stdout is
|
|
314
|
+
returns `true` if stdout is a TTY. always `false` in test mode.
|
|
260
315
|
```ts
|
|
261
316
|
if (isInteractive()) {
|
|
262
317
|
const s = spin('Loading...')
|
|
@@ -284,32 +339,32 @@ isColorEnabled() // true in an interactive terminal, false everywhere else
|
|
|
284
339
|
| `style.success(msg, meta?)` | green, prepends ✔ |
|
|
285
340
|
| `style.warn(msg, meta?)` | yellow, prepends ⚠ |
|
|
286
341
|
| `style.info(msg, meta?)` | blue, prepends ℹ |
|
|
287
|
-
| `style.debug(msg, meta?)` | gray+dim, 🔍 prefix, only when
|
|
342
|
+
| `style.debug(msg, meta?)` | gray+dim, 🔍 prefix, only when DEBUG is set |
|
|
288
343
|
| `style.muted(msg)` | gray, dimmed |
|
|
289
344
|
| `style.bold(msg)` | bold white |
|
|
290
345
|
| `style.highlight(msg)` | cyan |
|
|
291
346
|
| `style.divider(color?)` | 40 char horizontal rule, default gray |
|
|
292
347
|
| `style.table(data, color?)` | aligned key-value table, keys in cyan |
|
|
293
|
-
| `style.timestamp(msg, color?)` | prepends [HH:MM:SS],
|
|
294
|
-
| `style.group(label, lines[])` |
|
|
348
|
+
| `style.timestamp(msg, color?)` | prepends [HH:MM:SS], omitted in test mode |
|
|
349
|
+
| `style.group(label, lines[])` | labeled indented section |
|
|
295
350
|
| `style.list(items, options?)` | bulleted list, options: bullet, color, indent |
|
|
296
351
|
| `badge(text, color?)` | [text] in chosen color, default white |
|
|
297
|
-
| `box(text, color
|
|
298
|
-
| `columns(left, right, options?)` |
|
|
299
|
-
| `truncate(str, maxLength)` | truncate
|
|
300
|
-
| `spin(msg)` | animated spinner
|
|
352
|
+
| `box(text, color or options?)` | unicode border box with optional title |
|
|
353
|
+
| `columns(left, right, options?)` | side by side output, options: width, gap |
|
|
354
|
+
| `truncate(str, maxLength)` | truncate preserving ANSI codes |
|
|
355
|
+
| `spin(msg)` | animated spinner, returns succeed, fail, update |
|
|
301
356
|
| `strip(str)` | removes all ANSI escape codes |
|
|
357
|
+
| `paint(text, options?)` | raw ANSI composer |
|
|
302
358
|
| `setTheme(theme)` | override colors and icons globally |
|
|
303
359
|
| `resetTheme()` | restore default theme |
|
|
304
|
-
| `setIcons(icons)` | override icons for
|
|
305
|
-
| `setSilent(
|
|
306
|
-
| `setTestMode(
|
|
307
|
-
| `
|
|
308
|
-
| `
|
|
309
|
-
| `isColorEnabled()` | returns true if colors are active |
|
|
360
|
+
| `setIcons(icons)` | override icons for success, error, warn, info, debug |
|
|
361
|
+
| `setSilent(bool)` | suppress all output globally |
|
|
362
|
+
| `setTestMode(bool)` | deterministic output for snapshot testing |
|
|
363
|
+
| `isColorEnabled()` | true if colors are active |
|
|
364
|
+
| `isInteractive()` | true if stdout is a TTY, false in test mode |
|
|
310
365
|
|
|
311
366
|
---
|
|
312
367
|
|
|
313
368
|
## license
|
|
314
369
|
|
|
315
|
-
MIT © Abdullah Hashmi
|
|
370
|
+
MIT © Abdullah Hashmi
|