@reliverse/rempts 1.7.56 → 1.7.58
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 +5 -7
- package/bin/libs/input/input-mod.js +1 -1
- package/bin/libs/intro/intro-mod.js +1 -1
- package/bin/libs/msg-fmt/messages.js +1 -1
- package/bin/libs/select/select-prompt.js +3 -0
- package/bin/libs/spinner/spinner-mod.d.ts +255 -101
- package/bin/libs/spinner/spinner-mod.js +430 -231
- package/bin/libs/utils/prompt-end.js +3 -1
- package/bin/libs/utils/system.d.ts +1 -1
- package/bin/libs/utils/system.js +1 -1
- package/bin/mod.d.ts +2 -5
- package/bin/mod.js +25 -9
- package/bin/types.d.ts +4 -3
- package/package.json +6 -4
- package/bin/libs/msg-fmt/logger.d.ts +0 -17
- package/bin/libs/msg-fmt/logger.js +0 -103
- package/bin/libs/spinner/spinner-alias.d.ts +0 -2
- package/bin/libs/spinner/spinner-alias.js +0 -2
- package/bin/libs/task/progress.d.ts +0 -2
- package/bin/libs/task/progress.js +0 -57
- package/bin/libs/task/task-spin.d.ts +0 -15
- package/bin/libs/task/task-spin.js +0 -106
|
@@ -1,255 +1,454 @@
|
|
|
1
1
|
import { re } from "@reliverse/relico";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
import cliSpinners, { randomSpinner } from "cli-spinners";
|
|
3
|
+
import ora, {
|
|
4
|
+
oraPromise
|
|
5
|
+
} from "ora";
|
|
6
|
+
import prettyBytes from "pretty-bytes";
|
|
7
|
+
import prettyMilliseconds from "pretty-ms";
|
|
8
|
+
function isColorsEnabled(isSpinnerEnabledFlag) {
|
|
9
|
+
if (process.env["CLI_NO_COLOR"] === "1") return false;
|
|
10
|
+
return isSpinnerEnabledFlag;
|
|
11
|
+
}
|
|
12
|
+
function toStyler(input, fallback) {
|
|
13
|
+
if (!input) return fallback;
|
|
14
|
+
if (typeof input === "function") return input;
|
|
15
|
+
const fn = re[input];
|
|
16
|
+
if (typeof fn === "function") return fn;
|
|
17
|
+
return fallback;
|
|
18
|
+
}
|
|
19
|
+
const identity = (s) => s;
|
|
20
|
+
function isCIEnvironment() {
|
|
21
|
+
const { CI, GITHUB_ACTIONS, BUILD_NUMBER, RUN_ID } = process.env;
|
|
22
|
+
return CI === "true" || GITHUB_ACTIONS === "true" || typeof BUILD_NUMBER !== "undefined" || typeof RUN_ID !== "undefined";
|
|
23
|
+
}
|
|
24
|
+
const defaultStderr = process.stderr;
|
|
25
|
+
function isInteractive(stream = defaultStderr) {
|
|
26
|
+
return Boolean(stream && stream.isTTY);
|
|
27
|
+
}
|
|
28
|
+
function getDefaultEnabled(stream = defaultStderr) {
|
|
29
|
+
const disabledByEnv = process.env["CLI_NO_SPINNER"] === "1" || process.env["CLI_NO_COLOR"] === "1";
|
|
30
|
+
if (disabledByEnv) return false;
|
|
31
|
+
if (isCIEnvironment()) return false;
|
|
32
|
+
return isInteractive(stream);
|
|
33
|
+
}
|
|
34
|
+
export const defaultSpinnerOptions = {
|
|
35
|
+
color: "cyan",
|
|
36
|
+
spinner: "dots",
|
|
37
|
+
hideCursor: true,
|
|
38
|
+
indent: 0,
|
|
39
|
+
discardStdin: true,
|
|
40
|
+
respectEnv: true,
|
|
41
|
+
showTiming: false
|
|
42
|
+
};
|
|
43
|
+
export function isSpinnerEnabled(options) {
|
|
44
|
+
const stream = options?.stream ?? defaultStderr;
|
|
45
|
+
const respectEnv = options?.respectEnv !== false;
|
|
46
|
+
if (typeof options?.isEnabled === "boolean") return options.isEnabled;
|
|
47
|
+
return respectEnv ? getDefaultEnabled(stream) : true;
|
|
48
|
+
}
|
|
49
|
+
export function createSpinner(input) {
|
|
50
|
+
const base = typeof input === "string" ? { text: input } : { ...input ?? {} };
|
|
51
|
+
const stream = base.stream ?? defaultStderr;
|
|
52
|
+
const respectEnv = base.respectEnv !== false;
|
|
53
|
+
const isEnabled = base.isEnabled ?? (respectEnv ? getDefaultEnabled(stream) : true);
|
|
54
|
+
const isSilent = base.isSilent ?? false;
|
|
55
|
+
const resolvedColor = base.color ?? defaultSpinnerOptions.color ?? "cyan";
|
|
56
|
+
const resolvedSpinner = base.spinner ?? defaultSpinnerOptions.spinner ?? "dots";
|
|
57
|
+
const resolvedHideCursor = base.hideCursor ?? defaultSpinnerOptions.hideCursor ?? true;
|
|
58
|
+
const resolvedIndent = base.indent ?? defaultSpinnerOptions.indent ?? 0;
|
|
59
|
+
const resolvedDiscardStdin = base.discardStdin ?? defaultSpinnerOptions.discardStdin ?? true;
|
|
60
|
+
const options = {
|
|
61
|
+
// Defaults chosen to be broadly useful; callers can override
|
|
62
|
+
color: resolvedColor,
|
|
63
|
+
hideCursor: resolvedHideCursor,
|
|
64
|
+
indent: resolvedIndent,
|
|
65
|
+
stream,
|
|
66
|
+
isEnabled,
|
|
67
|
+
isSilent,
|
|
68
|
+
discardStdin: resolvedDiscardStdin,
|
|
69
|
+
...resolvedSpinner !== void 0 ? { spinner: resolvedSpinner } : {},
|
|
70
|
+
...base.interval !== void 0 ? { interval: base.interval } : {},
|
|
71
|
+
...base.prefixText !== void 0 ? { prefixText: base.prefixText } : {},
|
|
72
|
+
...base.suffixText !== void 0 ? { suffixText: base.suffixText } : {},
|
|
73
|
+
...base.text !== void 0 ? { text: base.text } : {}
|
|
74
|
+
};
|
|
75
|
+
const spinner = ora(options);
|
|
76
|
+
const colorsEnabled = isColorsEnabled(isEnabled);
|
|
77
|
+
const themeObj = base.theme ?? {};
|
|
78
|
+
const dim = colorsEnabled ? themeObj.dim ?? re.dim ?? identity : identity;
|
|
79
|
+
const info = colorsEnabled ? themeObj.info ?? re.cyan ?? identity : identity;
|
|
80
|
+
const success = colorsEnabled ? themeObj.success ?? re.green ?? identity : identity;
|
|
81
|
+
const error = colorsEnabled ? themeObj.error ?? re.red ?? identity : identity;
|
|
82
|
+
const progress = colorsEnabled ? themeObj.progress ?? re.cyan ?? identity : identity;
|
|
83
|
+
const rate = colorsEnabled ? themeObj.rate ?? re.cyan ?? identity : identity;
|
|
84
|
+
const bytesColor = colorsEnabled ? themeObj.bytes ?? re.cyan ?? identity : identity;
|
|
85
|
+
const percent = colorsEnabled ? themeObj.percentage ?? re.yellow ?? identity : identity;
|
|
86
|
+
spinner.__reTheme = { dim, info, success, error, progress, rate, bytesColor, percent };
|
|
87
|
+
spinner.__textStyler = toStyler(base.textColor, info);
|
|
88
|
+
spinner.__prefixStyler = toStyler(base.prefixColor, identity);
|
|
89
|
+
spinner.__suffixStyler = toStyler(base.suffixColor, identity);
|
|
90
|
+
spinner.__successStyler = toStyler(base.successColor, success);
|
|
91
|
+
spinner.__failStyler = toStyler(base.failColor, error);
|
|
92
|
+
if (options.text) {
|
|
93
|
+
const style = spinner.__textStyler;
|
|
94
|
+
spinner.text = style(options.text);
|
|
21
95
|
}
|
|
96
|
+
return spinner;
|
|
97
|
+
}
|
|
98
|
+
export async function withSpinnerPromise(action, options) {
|
|
99
|
+
return oraPromise(
|
|
100
|
+
action,
|
|
101
|
+
options
|
|
102
|
+
);
|
|
22
103
|
}
|
|
23
|
-
function
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
104
|
+
export async function withSpinner(textOrOptions, action, onSuccessText, onFailText) {
|
|
105
|
+
const startTime = Date.now();
|
|
106
|
+
const options = typeof textOrOptions === "string" ? { text: textOrOptions } : textOrOptions;
|
|
107
|
+
const spinner = createSpinner(textOrOptions).start();
|
|
108
|
+
try {
|
|
109
|
+
const result = await action(spinner);
|
|
110
|
+
const successMsg = getSuccessMessage(result, onSuccessText, options, startTime);
|
|
111
|
+
const style = spinner.__successStyler ?? identity;
|
|
112
|
+
spinner.succeed(successMsg ? style(successMsg) : void 0);
|
|
113
|
+
return result;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
const err = error;
|
|
116
|
+
const failMsg = getFailMessage(err, onFailText, options);
|
|
117
|
+
const style = spinner.__failStyler ?? identity;
|
|
118
|
+
spinner.fail(failMsg ? style(failMsg) : void 0);
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function getSuccessMessage(result, onSuccessText, options, startTime) {
|
|
123
|
+
let message;
|
|
124
|
+
if (typeof onSuccessText === "function") {
|
|
125
|
+
message = onSuccessText(result);
|
|
126
|
+
} else if (typeof onSuccessText === "string") {
|
|
127
|
+
message = onSuccessText;
|
|
128
|
+
} else if (options.defaultSuccess) {
|
|
129
|
+
message = options.defaultSuccess;
|
|
130
|
+
}
|
|
131
|
+
if (options.showTiming && message) {
|
|
132
|
+
const elapsed = Date.now() - startTime;
|
|
133
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
134
|
+
message = `${message} (${timing})`;
|
|
135
|
+
}
|
|
136
|
+
return message;
|
|
137
|
+
}
|
|
138
|
+
function getFailMessage(error, onFailText, options) {
|
|
139
|
+
if (typeof onFailText === "function") {
|
|
140
|
+
return onFailText(error);
|
|
141
|
+
} else if (typeof onFailText === "string") {
|
|
142
|
+
return onFailText;
|
|
143
|
+
} else if (options.defaultFail) {
|
|
144
|
+
return options.defaultFail;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export function updateSpinnerText(spinner, text, options) {
|
|
148
|
+
const { prefix, suffix } = options ?? {};
|
|
149
|
+
const styleText = spinner.__textStyler ?? identity;
|
|
150
|
+
const stylePrefix = spinner.__prefixStyler ?? identity;
|
|
151
|
+
const styleSuffix = spinner.__suffixStyler ?? identity;
|
|
152
|
+
const prefixStyled = prefix ? stylePrefix(prefix) : "";
|
|
153
|
+
const suffixStyled = suffix ? styleSuffix(suffix) : "";
|
|
154
|
+
const fullText = `${prefixStyled}${styleText(text)}${suffixStyled}`;
|
|
155
|
+
spinner.text = fullText;
|
|
156
|
+
}
|
|
157
|
+
export function stopAndPersist(spinner, options) {
|
|
158
|
+
spinner.stopAndPersist({
|
|
159
|
+
symbol: options.symbol ?? " ",
|
|
160
|
+
text: options.text ?? spinner.text,
|
|
161
|
+
prefixText: options.prefixText ?? spinner.prefixText,
|
|
162
|
+
suffixText: options.suffixText ?? spinner.suffixText
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
export function createTimedSpinner(input) {
|
|
166
|
+
const startTime = Date.now();
|
|
167
|
+
const options = typeof input === "string" ? { text: input } : { ...input ?? {} };
|
|
168
|
+
const spinner = createSpinner({ ...options, showTiming: true });
|
|
169
|
+
return {
|
|
170
|
+
spinner,
|
|
171
|
+
getElapsed: () => Date.now() - startTime,
|
|
172
|
+
succeedWithTiming: (text) => {
|
|
173
|
+
const elapsed = Date.now() - startTime;
|
|
174
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
175
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
176
|
+
const successStyle = spinner.__successStyler ?? identity;
|
|
177
|
+
const message = text ? `${successStyle(text)} ${dim(`(${timing})`)}` : void 0;
|
|
178
|
+
spinner.succeed(message);
|
|
179
|
+
},
|
|
180
|
+
failWithTiming: (text) => {
|
|
181
|
+
const elapsed = Date.now() - startTime;
|
|
182
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
183
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
184
|
+
const failStyle = spinner.__failStyler ?? identity;
|
|
185
|
+
const message = text ? `${failStyle(text)} ${dim(`(failed after ${timing})`)}` : void 0;
|
|
186
|
+
spinner.fail(message);
|
|
187
|
+
}
|
|
45
188
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
189
|
+
}
|
|
190
|
+
export function createSpinnerGroup(options) {
|
|
191
|
+
const { items, concurrent = false, ...baseOptions } = options;
|
|
192
|
+
const spinners2 = items.map((item, index) => {
|
|
193
|
+
const spinnerOptions = {
|
|
194
|
+
...baseOptions,
|
|
195
|
+
text: item,
|
|
196
|
+
indent: (baseOptions.indent ?? 0) + (concurrent ? 0 : index * 2)
|
|
197
|
+
};
|
|
198
|
+
return createSpinner(spinnerOptions);
|
|
199
|
+
});
|
|
200
|
+
return {
|
|
201
|
+
spinners: spinners2,
|
|
202
|
+
updateAll: (text) => {
|
|
203
|
+
for (const spinner of spinners2) {
|
|
204
|
+
updateSpinnerText(spinner, text);
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
succeedAll: (text) => {
|
|
208
|
+
for (const spinner of spinners2) {
|
|
209
|
+
const style = spinner.__successStyler ?? identity;
|
|
210
|
+
spinner.succeed(text ? style(text) : void 0);
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
failAll: (text) => {
|
|
214
|
+
for (const spinner of spinners2) {
|
|
215
|
+
const style = spinner.__failStyler ?? identity;
|
|
216
|
+
spinner.fail(text ? style(text) : void 0);
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
stopAll: () => {
|
|
220
|
+
for (const spinner of spinners2) {
|
|
221
|
+
spinner.stop();
|
|
53
222
|
}
|
|
54
223
|
}
|
|
55
224
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
225
|
+
}
|
|
226
|
+
export async function withEnhancedSpinner(textOrOptions, action) {
|
|
227
|
+
const startTime = Date.now();
|
|
228
|
+
const options = typeof textOrOptions === "string" ? { text: textOrOptions, showTiming: false } : { showTiming: false, ...textOrOptions };
|
|
229
|
+
const baseSpinner = createSpinner(options).start();
|
|
230
|
+
const enhancedSpinner = Object.assign(baseSpinner, {
|
|
231
|
+
updateText: (text, updateOptions) => {
|
|
232
|
+
updateSpinnerText(baseSpinner, text, updateOptions);
|
|
233
|
+
},
|
|
234
|
+
setProgress: (current, total, text) => {
|
|
235
|
+
const progressText = text ? `${text} (${current}/${total})` : `${current}/${total}`;
|
|
236
|
+
baseSpinner.text = progressText;
|
|
66
237
|
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
238
|
+
});
|
|
239
|
+
try {
|
|
240
|
+
const result = await action(enhancedSpinner);
|
|
241
|
+
let successText = options.successText;
|
|
242
|
+
if (options.showTiming && successText) {
|
|
243
|
+
const elapsed = Date.now() - startTime;
|
|
244
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
245
|
+
successText = `${successText} (${timing})`;
|
|
246
|
+
}
|
|
247
|
+
baseSpinner.succeed(successText);
|
|
248
|
+
return result;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
const err = error;
|
|
251
|
+
let failText = options.failText;
|
|
252
|
+
if (options.showTiming && failText) {
|
|
253
|
+
const elapsed = Date.now() - startTime;
|
|
254
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
255
|
+
failText = `${failText} (failed after ${timing})`;
|
|
256
|
+
}
|
|
257
|
+
baseSpinner.fail(failText);
|
|
258
|
+
throw err;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
export function isSpinnerRunning(spinner) {
|
|
262
|
+
return spinner.isSpinning;
|
|
263
|
+
}
|
|
264
|
+
export function safeStopSpinner(spinner) {
|
|
265
|
+
if (spinner?.isSpinning) {
|
|
266
|
+
spinner.stop();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
export function createBuildSpinner(operation, options) {
|
|
270
|
+
const spinner = createSpinner({ text: operation, ...options }).start();
|
|
271
|
+
return {
|
|
272
|
+
spinner,
|
|
273
|
+
complete: (message) => {
|
|
274
|
+
const successStyle = spinner.__successStyler ?? identity;
|
|
275
|
+
spinner.succeed(successStyle(message ?? `${operation} completed successfully!`));
|
|
276
|
+
},
|
|
277
|
+
error: (error) => {
|
|
278
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
279
|
+
const failStyle = spinner.__failStyler ?? identity;
|
|
280
|
+
spinner.fail(failStyle(`${operation} failed: ${errorMessage}`));
|
|
281
|
+
},
|
|
282
|
+
updateProgress: (step) => {
|
|
283
|
+
const info = spinner.__reTheme?.info ?? identity;
|
|
284
|
+
updateSpinnerText(spinner, `${operation} - ${info(step)}`);
|
|
76
285
|
}
|
|
77
286
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
if (options.silent || !interactive) {
|
|
92
|
-
console.log(options.prefixText ? `${options.prefixText} ${options.text}` : options.text);
|
|
93
|
-
state.isActive = true;
|
|
94
|
-
state.startTime = Date.now();
|
|
95
|
-
return controls;
|
|
287
|
+
}
|
|
288
|
+
export function createFileProgressSpinner(operation, options) {
|
|
289
|
+
const { totalBytes, showBytes = true, showRate = false, ...spinnerOptions } = options ?? {};
|
|
290
|
+
const startTime = Date.now();
|
|
291
|
+
const spinner = createSpinner({ text: operation, ...spinnerOptions }).start();
|
|
292
|
+
return {
|
|
293
|
+
spinner,
|
|
294
|
+
updateProgress: (bytesProcessed, fileName) => {
|
|
295
|
+
let progressText = operation;
|
|
296
|
+
if (fileName) {
|
|
297
|
+
const info = spinner.__reTheme?.info ?? identity;
|
|
298
|
+
progressText += ` - ${info(fileName)}`;
|
|
96
299
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
registerHooks();
|
|
104
|
-
loop = setInterval(() => {
|
|
105
|
-
if (process.env["CI"] && state.text === state.prevMessage) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
clearPrevMessage();
|
|
109
|
-
state.prevMessage = state.text;
|
|
110
|
-
const frame = re.magenta((options.frames ?? defaultFrames)[frameIndex] ?? "");
|
|
111
|
-
if (process.env["CI"]) {
|
|
112
|
-
process.stdout.write(`${frame} ${state.text}...`);
|
|
113
|
-
} else if (options.indicator === "timer") {
|
|
114
|
-
process.stdout.write(`${frame} ${state.text} ${formatTimer(state.origin)}`);
|
|
300
|
+
if (showBytes) {
|
|
301
|
+
if (totalBytes) {
|
|
302
|
+
const percentage = Math.round(bytesProcessed / totalBytes * 100);
|
|
303
|
+
const bytesColor = spinner.__reTheme?.bytesColor ?? identity;
|
|
304
|
+
const percent = spinner.__reTheme?.percent ?? identity;
|
|
305
|
+
progressText += ` (${bytesColor(prettyBytes(bytesProcessed))}/${bytesColor(prettyBytes(totalBytes))} - ${percent(`${percentage}%`)})`;
|
|
115
306
|
} else {
|
|
116
|
-
const
|
|
117
|
-
|
|
307
|
+
const bytesColor = spinner.__reTheme?.bytesColor ?? identity;
|
|
308
|
+
progressText += ` (${bytesColor(prettyBytes(bytesProcessed))})`;
|
|
118
309
|
}
|
|
119
|
-
frameIndex = (frameIndex + 1) % (options.frames ?? defaultFrames).length;
|
|
120
|
-
state.indicatorTimer = state.indicatorTimer < 4 ? state.indicatorTimer + 0.125 : 0;
|
|
121
|
-
}, options.delay ?? defaultDelay);
|
|
122
|
-
return controls;
|
|
123
|
-
},
|
|
124
|
-
stop: (text, code = 0) => {
|
|
125
|
-
if (!state.isActive) return;
|
|
126
|
-
state.isActive = false;
|
|
127
|
-
clearInterval(loop);
|
|
128
|
-
clearPrevMessage();
|
|
129
|
-
const step = code === 0 ? re.green("\u2713") : code === 1 ? re.red("\u2717") : re.red("\u2717");
|
|
130
|
-
const finalText = text ?? state.text;
|
|
131
|
-
if (options.indicator === "timer") {
|
|
132
|
-
process.stdout.write(`${step} ${finalText} ${formatTimer(state.origin)}
|
|
133
|
-
`);
|
|
134
|
-
} else {
|
|
135
|
-
process.stdout.write(`${step} ${finalText}
|
|
136
|
-
`);
|
|
137
|
-
}
|
|
138
|
-
clearHooks();
|
|
139
|
-
if (unblock) unblock();
|
|
140
|
-
},
|
|
141
|
-
setText: (text) => {
|
|
142
|
-
state.text = removeTrailingDots(text);
|
|
143
|
-
options.text = text;
|
|
144
|
-
},
|
|
145
|
-
setProgress: (progress) => {
|
|
146
|
-
const progressText = formatProgress(progress);
|
|
147
|
-
const newText = `${state.text} [${progressText}]`;
|
|
148
|
-
state.text = newText;
|
|
149
|
-
options.text = newText;
|
|
150
|
-
},
|
|
151
|
-
succeed: (text) => {
|
|
152
|
-
const successText = text ?? options.successText ?? state.text;
|
|
153
|
-
controls.stop(successText, 0);
|
|
154
|
-
},
|
|
155
|
-
fail: (text) => {
|
|
156
|
-
const failText = text ?? options.failText ?? state.text;
|
|
157
|
-
controls.stop(failText, 2);
|
|
158
|
-
},
|
|
159
|
-
warn: (text) => {
|
|
160
|
-
const warnText = text ?? state.text;
|
|
161
|
-
controls.stop(warnText, 0);
|
|
162
|
-
},
|
|
163
|
-
info: (text) => {
|
|
164
|
-
const infoText = text ?? state.text;
|
|
165
|
-
controls.stop(infoText, 0);
|
|
166
|
-
},
|
|
167
|
-
isSpinning: () => {
|
|
168
|
-
return state.isActive && !state.isPaused;
|
|
169
|
-
},
|
|
170
|
-
clear: () => {
|
|
171
|
-
clearPrevMessage();
|
|
172
|
-
},
|
|
173
|
-
getElapsedTime: () => {
|
|
174
|
-
if (!state.startTime) return 0;
|
|
175
|
-
const currentTime = Date.now();
|
|
176
|
-
return currentTime - state.startTime - state.pausedTime;
|
|
177
|
-
},
|
|
178
|
-
pause: () => {
|
|
179
|
-
if (state.isActive && !state.isPaused) {
|
|
180
|
-
clearInterval(loop);
|
|
181
|
-
state.isPaused = true;
|
|
182
310
|
}
|
|
311
|
+
spinner.text = progressText;
|
|
183
312
|
},
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
313
|
+
updateRate: (bytesPerSecond) => {
|
|
314
|
+
if (showRate) {
|
|
315
|
+
const currentText = spinner.text;
|
|
316
|
+
const rate = spinner.__reTheme?.rate ?? identity;
|
|
317
|
+
const rateText = rate(`${prettyBytes(bytesPerSecond)}/s`);
|
|
318
|
+
spinner.text = `${currentText} @ ${rateText}`;
|
|
189
319
|
}
|
|
190
320
|
},
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
321
|
+
complete: (message) => {
|
|
322
|
+
const elapsed = Date.now() - startTime;
|
|
323
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
324
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
325
|
+
const successStyle = spinner.__successStyler ?? identity;
|
|
326
|
+
const successMessage = successStyle(message ?? `${operation} completed successfully`);
|
|
327
|
+
spinner.succeed(`${successMessage} ${dim(`(${timing})`)}`);
|
|
197
328
|
},
|
|
198
|
-
|
|
199
|
-
|
|
329
|
+
error: (error) => {
|
|
330
|
+
const elapsed = Date.now() - startTime;
|
|
331
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
332
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
333
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
334
|
+
const failStyle = spinner.__failStyler ?? identity;
|
|
335
|
+
spinner.fail(
|
|
336
|
+
`${failStyle(`${operation} failed: ${errorMessage}`)} ${dim(`(after ${timing})`)}`
|
|
337
|
+
);
|
|
200
338
|
}
|
|
201
339
|
};
|
|
202
|
-
return controls;
|
|
203
340
|
}
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
} finally {
|
|
214
|
-
spinner.dispose();
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
useSpinner.nested = (parentOptions) => {
|
|
218
|
-
const parentSpinner = useSpinner({
|
|
219
|
-
...parentOptions,
|
|
220
|
-
silent: true
|
|
221
|
-
// Parent is silent, children will show progress
|
|
222
|
-
});
|
|
341
|
+
export function createMultiStepSpinner(operationName, steps, options) {
|
|
342
|
+
const startTime = Date.now();
|
|
343
|
+
let currentStepIndex = 0;
|
|
344
|
+
const totalSteps = steps.length;
|
|
345
|
+
const getStepText = (stepIndex) => {
|
|
346
|
+
const step = steps[stepIndex];
|
|
347
|
+
return `${operationName} - ${step} (${stepIndex + 1}/${totalSteps})`;
|
|
348
|
+
};
|
|
349
|
+
const spinner = createSpinner({ text: getStepText(0), ...options }).start();
|
|
223
350
|
return {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
};
|
|
237
|
-
|
|
351
|
+
spinner,
|
|
352
|
+
nextStep: (stepIndex) => {
|
|
353
|
+
if (stepIndex !== void 0) {
|
|
354
|
+
currentStepIndex = Math.min(stepIndex, totalSteps - 1);
|
|
355
|
+
} else {
|
|
356
|
+
currentStepIndex = Math.min(currentStepIndex + 1, totalSteps - 1);
|
|
357
|
+
}
|
|
358
|
+
const text = getStepText(currentStepIndex);
|
|
359
|
+
updateSpinnerText(spinner, text);
|
|
360
|
+
},
|
|
361
|
+
complete: (message) => {
|
|
362
|
+
const elapsed = Date.now() - startTime;
|
|
363
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
364
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
365
|
+
const successStyle = spinner.__successStyler ?? identity;
|
|
366
|
+
const successMessage = successStyle(message ?? `${operationName} completed successfully`);
|
|
367
|
+
spinner.succeed(`${successMessage} ${dim(`(${timing})`)}`);
|
|
368
|
+
},
|
|
369
|
+
error: (error, stepIndex) => {
|
|
370
|
+
const elapsed = Date.now() - startTime;
|
|
371
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
372
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
373
|
+
const stepInfo = stepIndex !== void 0 ? ` at step ${stepIndex + 1}` : "";
|
|
374
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
375
|
+
const failStyle = spinner.__failStyler ?? identity;
|
|
376
|
+
spinner.fail(
|
|
377
|
+
`${failStyle(`${operationName} failed${stepInfo}: ${errorMessage}`)} ${dim(`(after ${timing})`)}`
|
|
378
|
+
);
|
|
379
|
+
},
|
|
380
|
+
getCurrentStep: () => currentStepIndex
|
|
238
381
|
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const
|
|
382
|
+
}
|
|
383
|
+
export function formatSpinnerTiming(startTime, options) {
|
|
384
|
+
const elapsed = Date.now() - startTime;
|
|
385
|
+
const pmOptions = { compact: !options?.verbose };
|
|
386
|
+
if (options?.verbose !== void 0) pmOptions["verbose"] = options.verbose;
|
|
387
|
+
return prettyMilliseconds(elapsed, pmOptions);
|
|
388
|
+
}
|
|
389
|
+
export function formatSpinnerBytes(bytes, options) {
|
|
390
|
+
return prettyBytes(bytes, options);
|
|
391
|
+
}
|
|
392
|
+
export function formatSpinnerElapsed(elapsed, options) {
|
|
393
|
+
const pmOptions = { compact: !options?.verbose };
|
|
394
|
+
if (options?.verbose !== void 0) pmOptions["verbose"] = options.verbose;
|
|
395
|
+
return prettyMilliseconds(elapsed, pmOptions);
|
|
396
|
+
}
|
|
397
|
+
export function createTransferSpinner(operation, options) {
|
|
398
|
+
const { totalBytes, showRate = true, ...spinnerOptions } = options ?? {};
|
|
242
399
|
const startTime = Date.now();
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
400
|
+
const spinner = createSpinner({ text: operation, ...spinnerOptions }).start();
|
|
401
|
+
return {
|
|
402
|
+
spinner,
|
|
403
|
+
updateBytes: (bytesTransferred, fileName) => {
|
|
404
|
+
let text = operation;
|
|
405
|
+
if (fileName) {
|
|
406
|
+
const info = spinner.__reTheme?.info ?? identity;
|
|
407
|
+
text += ` - ${info(fileName)}`;
|
|
408
|
+
}
|
|
409
|
+
if (totalBytes) {
|
|
410
|
+
const percentage = Math.round(bytesTransferred / totalBytes * 100);
|
|
411
|
+
const bytesColor = spinner.__reTheme?.bytesColor ?? identity;
|
|
412
|
+
const percent = spinner.__reTheme?.percent ?? identity;
|
|
413
|
+
text += ` (${bytesColor(prettyBytes(bytesTransferred))}/${bytesColor(prettyBytes(totalBytes))} - ${percent(`${percentage}%`)})`;
|
|
414
|
+
} else {
|
|
415
|
+
const bytesColor = spinner.__reTheme?.bytesColor ?? identity;
|
|
416
|
+
text += ` (${bytesColor(prettyBytes(bytesTransferred))})`;
|
|
417
|
+
}
|
|
418
|
+
spinner.text = text;
|
|
419
|
+
},
|
|
420
|
+
updateRate: (bytesPerSecond) => {
|
|
421
|
+
if (showRate) {
|
|
422
|
+
const currentText = spinner.text;
|
|
423
|
+
const rate = spinner.__reTheme?.rate ?? identity;
|
|
424
|
+
const rateText = rate(`${prettyBytes(bytesPerSecond)}/s`);
|
|
425
|
+
spinner.text = `${currentText} @ ${rateText}`;
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
complete: (message, totalBytesTransferred) => {
|
|
429
|
+
const elapsed = Date.now() - startTime;
|
|
430
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
431
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
432
|
+
const successStyle = spinner.__successStyler ?? identity;
|
|
433
|
+
let successMessage = successStyle(message ?? `${operation} completed successfully`);
|
|
434
|
+
if (totalBytesTransferred) {
|
|
435
|
+
const bytesColor = spinner.__reTheme?.bytesColor ?? identity;
|
|
436
|
+
successMessage += ` (${bytesColor(prettyBytes(totalBytesTransferred))})`;
|
|
437
|
+
}
|
|
438
|
+
successMessage += ` ${dim(`in ${timing}`)}`;
|
|
439
|
+
spinner.succeed(successMessage);
|
|
440
|
+
},
|
|
441
|
+
error: (error) => {
|
|
442
|
+
const elapsed = Date.now() - startTime;
|
|
443
|
+
const timing = prettyMilliseconds(elapsed, { compact: true });
|
|
444
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
445
|
+
const dim = spinner.__reTheme?.dim ?? identity;
|
|
446
|
+
const failStyle = spinner.__failStyler ?? identity;
|
|
447
|
+
spinner.fail(
|
|
448
|
+
`${failStyle(`${operation} failed: ${errorMessage}`)} ${dim(`(after ${timing})`)}`
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
export const spinners = cliSpinners;
|
|
454
|
+
export { randomSpinner, prettyBytes, prettyMilliseconds };
|