bananass-utils-console 0.8.0 → 0.9.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/README.md +11 -153
- package/build/icons.d.ts +31 -0
- package/{src/icons → build}/icons.js +10 -51
- package/build/{is-interactive/is-interactive.d.ts → is-interactive.d.ts} +5 -4
- package/{src/is-interactive → build}/is-interactive.js +4 -8
- package/build/{is-unicode-supported/is-unicode-supported.d.ts → is-unicode-supported.d.ts} +6 -1
- package/{src/is-unicode-supported → build}/is-unicode-supported.js +16 -24
- package/build/{logger/logger.d.ts → logger.d.ts} +32 -35
- package/build/logger.js +163 -0
- package/build/{spinner/spinner.d.ts → spinner.d.ts} +57 -78
- package/build/spinner.js +277 -0
- package/build/theme.d.ts +64 -0
- package/{src/theme → build}/theme.js +31 -46
- package/package.json +24 -25
- package/build/icons/icons.d.ts +0 -28
- package/build/icons/index.d.ts +0 -1
- package/build/is-interactive/index.d.ts +0 -2
- package/build/is-unicode-supported/index.d.ts +0 -2
- package/build/logger/index.d.ts +0 -2
- package/build/spinner/index.d.ts +0 -2
- package/build/theme/index.d.ts +0 -1
- package/build/theme/theme.d.ts +0 -60
- package/src/icons/index.js +0 -1
- package/src/is-interactive/index.js +0 -3
- package/src/is-unicode-supported/index.js +0 -3
- package/src/logger/index.js +0 -3
- package/src/logger/logger.js +0 -208
- package/src/spinner/index.js +0 -3
- package/src/spinner/spinner.js +0 -388
- package/src/theme/index.js +0 -1
package/src/spinner/spinner.js
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Console spinner.
|
|
3
|
-
* @module bananass-utils-console/spinner
|
|
4
|
-
* @license MIT Portions of this code were borrowed from [`yocto-spinner`](https://github.com/sindresorhus/yocto-spinner).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// --------------------------------------------------------------------------------
|
|
8
|
-
// Import
|
|
9
|
-
// --------------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
import { styleText } from 'node:util';
|
|
12
|
-
import isInteractive from '../is-interactive/index.js';
|
|
13
|
-
import {
|
|
14
|
-
successIcon,
|
|
15
|
-
errorIcon,
|
|
16
|
-
warningIcon,
|
|
17
|
-
infoIcon,
|
|
18
|
-
defaultSpinner,
|
|
19
|
-
} from '../icons/index.js';
|
|
20
|
-
|
|
21
|
-
// --------------------------------------------------------------------------------
|
|
22
|
-
// Typedefs
|
|
23
|
-
// --------------------------------------------------------------------------------
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @typedef {"black"|"blackBright"|"blue"|"blueBright"|"cyan"|"cyanBright"|"gray"|"green"|"greenBright"|"grey"|"magenta"|"magentaBright"|"red"|"redBright"|"white"|"whiteBright"|"yellow"|"yellowBright"} ForegroundColors
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {object} SpinnerStyle
|
|
31
|
-
* @property {string[]} frames
|
|
32
|
-
* @property {number} interval
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @typedef {object} Options Spinner options.
|
|
37
|
-
* @property {string | undefined} [text] Text to display next to the spinner. (default: `''`)
|
|
38
|
-
* @property {ForegroundColors | undefined} [color] The color of the spinner. (default: `'yellow'`)
|
|
39
|
-
* @property {NodeJS.WriteStream | undefined} [stream] The stream to which the spinner is written. (default: `process.stderr`)
|
|
40
|
-
* @property {boolean | undefined} [isInteractive] Whether the spinner should be interactive. (default: Auto-detected)
|
|
41
|
-
* @property {SpinnerStyle | undefined} [spinner]
|
|
42
|
-
* Customize the spinner animation with a custom set of frames and interval.
|
|
43
|
-
*
|
|
44
|
-
* ```
|
|
45
|
-
* {
|
|
46
|
-
* frames: ['-', '\\', '|', '/'],
|
|
47
|
-
* interval: 100,
|
|
48
|
-
* }
|
|
49
|
-
* ```
|
|
50
|
-
*
|
|
51
|
-
* Pass in any spinner from [`cli-spinners`](https://github.com/sindresorhus/cli-spinners).
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
// --------------------------------------------------------------------------------
|
|
55
|
-
// Class
|
|
56
|
-
// --------------------------------------------------------------------------------
|
|
57
|
-
|
|
58
|
-
class Spinner {
|
|
59
|
-
// ------------------------------------------------------------------------------
|
|
60
|
-
// Private Properties
|
|
61
|
-
// ------------------------------------------------------------------------------
|
|
62
|
-
|
|
63
|
-
/** @type {SpinnerStyle['frames']} */
|
|
64
|
-
#frames;
|
|
65
|
-
/** @type {SpinnerStyle['interval']} */
|
|
66
|
-
#interval;
|
|
67
|
-
/** @type {number} */
|
|
68
|
-
#currentFrame = -1;
|
|
69
|
-
/** @type {NodeJS.Timeout | undefined} */
|
|
70
|
-
#timer = undefined;
|
|
71
|
-
/** @type {string} */
|
|
72
|
-
#text;
|
|
73
|
-
/** @type {NodeJS.WriteStream} */
|
|
74
|
-
#stream;
|
|
75
|
-
/** @type {ForegroundColors} */
|
|
76
|
-
#color;
|
|
77
|
-
/** @type {number} */
|
|
78
|
-
#lines = 0;
|
|
79
|
-
/** @type {boolean} */
|
|
80
|
-
#isInteractive;
|
|
81
|
-
/** @type {(signal: string) => void} */
|
|
82
|
-
#exitHandlerBound;
|
|
83
|
-
/** @type {number} */
|
|
84
|
-
#lastSpinnerFrameTime = 0;
|
|
85
|
-
|
|
86
|
-
/** @param {Options} options */
|
|
87
|
-
constructor(options = {}) {
|
|
88
|
-
const spinner = options.spinner ?? defaultSpinner;
|
|
89
|
-
|
|
90
|
-
this.#frames = spinner.frames;
|
|
91
|
-
this.#interval = spinner.interval;
|
|
92
|
-
this.#text = options.text ?? '';
|
|
93
|
-
this.#stream = options.stream ?? process.stderr;
|
|
94
|
-
this.#color = options.color ?? 'yellow';
|
|
95
|
-
this.#isInteractive = options.isInteractive ?? isInteractive(this.#stream);
|
|
96
|
-
this.#exitHandlerBound = this.#exitHandler.bind(this);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ------------------------------------------------------------------------------
|
|
100
|
-
// Private Methods
|
|
101
|
-
// ------------------------------------------------------------------------------
|
|
102
|
-
|
|
103
|
-
/** @param {string} symbol @param {string} [text] */
|
|
104
|
-
#symbolStop(symbol, text = this.#text) {
|
|
105
|
-
return this.stop(`${symbol} ${text}`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
#render() {
|
|
109
|
-
const currentTime = Date.now();
|
|
110
|
-
|
|
111
|
-
// Ensure we only update the spinner frame at the wanted interval, even if the render method is called more often.
|
|
112
|
-
if (
|
|
113
|
-
this.#currentFrame === -1 ||
|
|
114
|
-
currentTime - this.#lastSpinnerFrameTime >= this.#interval
|
|
115
|
-
) {
|
|
116
|
-
this.#currentFrame = (this.#currentFrame + 1) % this.#frames.length;
|
|
117
|
-
this.#lastSpinnerFrameTime = currentTime;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const color = this.#color ?? 'yellow';
|
|
121
|
-
const frame = this.#frames[this.#currentFrame];
|
|
122
|
-
let string = `${styleText(color, frame)} ${this.#text}`;
|
|
123
|
-
|
|
124
|
-
if (!this.#isInteractive) {
|
|
125
|
-
string += '\n';
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
this.clear();
|
|
129
|
-
this.#write(string);
|
|
130
|
-
|
|
131
|
-
if (this.#isInteractive) {
|
|
132
|
-
this.#lines = this.#lineCount(string);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** @param {string} text */
|
|
137
|
-
#write(text) {
|
|
138
|
-
this.#stream.write(text);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** @param {string} text */
|
|
142
|
-
#lineCount(text) {
|
|
143
|
-
const width = this.#stream.columns ?? 80;
|
|
144
|
-
const lines = text.split('\n');
|
|
145
|
-
|
|
146
|
-
let lineCount = 0;
|
|
147
|
-
|
|
148
|
-
for (const line of lines) {
|
|
149
|
-
lineCount += Math.max(1, Math.ceil(line.length / width));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return lineCount;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
#hideCursor() {
|
|
156
|
-
if (this.#isInteractive) {
|
|
157
|
-
this.#write('\u001B[?25l');
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
#showCursor() {
|
|
162
|
-
if (this.#isInteractive) {
|
|
163
|
-
this.#write('\u001B[?25h');
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
#subscribeToProcessEvents() {
|
|
168
|
-
process.once('SIGINT', this.#exitHandlerBound);
|
|
169
|
-
process.once('SIGTERM', this.#exitHandlerBound);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
#unsubscribeFromProcessEvents() {
|
|
173
|
-
process.off('SIGINT', this.#exitHandlerBound);
|
|
174
|
-
process.off('SIGTERM', this.#exitHandlerBound);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** @param {string} signal */
|
|
178
|
-
#exitHandler(signal) {
|
|
179
|
-
if (this.isSpinning) {
|
|
180
|
-
this.stop();
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// SIGINT: 128 + 2, SIGTERM: 128 + 15
|
|
184
|
-
const exitCode = signal === 'SIGINT' ? 130 : signal === 'SIGTERM' ? 143 : 1;
|
|
185
|
-
process.exit(exitCode);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// ------------------------------------------------------------------------------
|
|
189
|
-
// Public Methods
|
|
190
|
-
// ------------------------------------------------------------------------------
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Starts the spinner.
|
|
194
|
-
*
|
|
195
|
-
* Optionally, updates the text.
|
|
196
|
-
*
|
|
197
|
-
* @param {string} [text] The text to display next to the spinner.
|
|
198
|
-
* @returns The spinner instance.
|
|
199
|
-
*/
|
|
200
|
-
start(text) {
|
|
201
|
-
if (text) {
|
|
202
|
-
this.#text = text;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (this.isSpinning) {
|
|
206
|
-
return this;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
this.#hideCursor();
|
|
210
|
-
this.#render();
|
|
211
|
-
this.#subscribeToProcessEvents();
|
|
212
|
-
|
|
213
|
-
this.#timer = setInterval(() => {
|
|
214
|
-
this.#render();
|
|
215
|
-
}, this.#interval);
|
|
216
|
-
|
|
217
|
-
return this;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Stops the spinner.
|
|
222
|
-
*
|
|
223
|
-
* Optionally displays a final message.
|
|
224
|
-
*
|
|
225
|
-
* @param {string} [finalText] The final text to display after stopping the spinner.
|
|
226
|
-
* @returns The spinner instance.
|
|
227
|
-
*/
|
|
228
|
-
stop(finalText) {
|
|
229
|
-
if (!this.isSpinning) {
|
|
230
|
-
return this;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
clearInterval(this.#timer);
|
|
234
|
-
this.#timer = undefined;
|
|
235
|
-
this.#showCursor();
|
|
236
|
-
this.clear();
|
|
237
|
-
this.#unsubscribeFromProcessEvents();
|
|
238
|
-
|
|
239
|
-
if (finalText) {
|
|
240
|
-
this.#stream.write(`${finalText}\n`);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return this;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Stops the spinner and displays a success symbol with the message.
|
|
248
|
-
*
|
|
249
|
-
* @param {string} [text] The success message to display.
|
|
250
|
-
* @returns The spinner instance.
|
|
251
|
-
*/
|
|
252
|
-
success(text) {
|
|
253
|
-
return this.#symbolStop(successIcon, text);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Stops the spinner and displays an error symbol with the message.
|
|
258
|
-
*
|
|
259
|
-
* @param {string} [text] The error message to display.
|
|
260
|
-
* @returns The spinner instance.
|
|
261
|
-
*/
|
|
262
|
-
error(text) {
|
|
263
|
-
return this.#symbolStop(errorIcon, text);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Stops the spinner and displays a warning symbol with the message.
|
|
268
|
-
*
|
|
269
|
-
* @param {string} [text] The warning message to display.
|
|
270
|
-
* @returns The spinner instance.
|
|
271
|
-
*/
|
|
272
|
-
warning(text) {
|
|
273
|
-
return this.#symbolStop(warningIcon, text);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Stops the spinner and displays an info symbol with the message.
|
|
278
|
-
*
|
|
279
|
-
* @param {string} [text] The info message to display.
|
|
280
|
-
* @returns The spinner instance.
|
|
281
|
-
*/
|
|
282
|
-
info(text) {
|
|
283
|
-
return this.#symbolStop(infoIcon, text);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Clears the spinner.
|
|
288
|
-
*
|
|
289
|
-
* @returns The spinner instance.
|
|
290
|
-
*/
|
|
291
|
-
clear() {
|
|
292
|
-
if (!this.#isInteractive) {
|
|
293
|
-
return this;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
this.#stream.cursorTo(0);
|
|
297
|
-
|
|
298
|
-
for (let index = 0; index < this.#lines; index++) {
|
|
299
|
-
if (index > 0) {
|
|
300
|
-
this.#stream.moveCursor(0, -1);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
this.#stream.clearLine(1);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
this.#lines = 0;
|
|
307
|
-
|
|
308
|
-
return this;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// ------------------------------------------------------------------------------
|
|
312
|
-
// Getters and Setters
|
|
313
|
-
// ------------------------------------------------------------------------------
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Change the text displayed next to the spinner.
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* spinner.text = 'New text';
|
|
320
|
-
*/
|
|
321
|
-
get text() {
|
|
322
|
-
return this.#text;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Change the text displayed next to the spinner.
|
|
327
|
-
*
|
|
328
|
-
* @example
|
|
329
|
-
* spinner.text = 'New text';
|
|
330
|
-
*/
|
|
331
|
-
set text(value) {
|
|
332
|
-
this.#text = value ?? '';
|
|
333
|
-
this.#render();
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Change the spinner color.
|
|
338
|
-
*/
|
|
339
|
-
get color() {
|
|
340
|
-
return this.#color;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Change the spinner color.
|
|
345
|
-
*/
|
|
346
|
-
set color(value) {
|
|
347
|
-
this.#color = value;
|
|
348
|
-
this.#render();
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Returns whether the spinner is currently spinning.
|
|
353
|
-
*/
|
|
354
|
-
get isSpinning() {
|
|
355
|
-
return this.#timer !== undefined;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// --------------------------------------------------------------------------------
|
|
360
|
-
// Export
|
|
361
|
-
// --------------------------------------------------------------------------------
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Create a new spinner instance.
|
|
365
|
-
*
|
|
366
|
-
* @param {Options} [options]
|
|
367
|
-
* @returns {Spinner} A new spinner instance.
|
|
368
|
-
*
|
|
369
|
-
* @example
|
|
370
|
-
* import createSpinner from 'bananass-utils-console/spinner';
|
|
371
|
-
*
|
|
372
|
-
* const spinner = createSpinner({
|
|
373
|
-
* text: 'Loading…'
|
|
374
|
-
* color: 'yellow',
|
|
375
|
-
* stream: process.stderr,
|
|
376
|
-
* spinner: {
|
|
377
|
-
* frames: ['-', '\\', '|', '/'],
|
|
378
|
-
* interval: 100,
|
|
379
|
-
* },
|
|
380
|
-
* }).start();
|
|
381
|
-
*
|
|
382
|
-
* setTimeout(() => {
|
|
383
|
-
* spinner.success('Success!');
|
|
384
|
-
* }, 2000);
|
|
385
|
-
*/
|
|
386
|
-
export default function createSpinner(options) {
|
|
387
|
-
return new Spinner(options);
|
|
388
|
-
}
|
package/src/theme/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './theme.js';
|