@mudah-cli/animation 0.1.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/dist/frames.d.ts +8 -0
- package/dist/frames.js +24 -0
- package/dist/frames.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/progress.d.ts +42 -0
- package/dist/progress.js +80 -0
- package/dist/progress.js.map +1 -0
- package/dist/spinner.d.ts +45 -0
- package/dist/spinner.js +90 -0
- package/dist/spinner.js.map +1 -0
- package/dist/tasks.d.ts +41 -0
- package/dist/tasks.js +89 -0
- package/dist/tasks.js.map +1 -0
- package/package.json +26 -0
package/dist/frames.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface SpinnerStyle {
|
|
2
|
+
/** One frame per entry, cycled in order. */
|
|
3
|
+
readonly frames: readonly string[];
|
|
4
|
+
/** Milliseconds per frame. */
|
|
5
|
+
readonly interval: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const spinnerStyles: Record<string, SpinnerStyle>;
|
|
8
|
+
export declare const defaultSpinner: SpinnerStyle;
|
package/dist/frames.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const spinnerStyles = {
|
|
2
|
+
/** Braille dots — the classic busy indicator. */
|
|
3
|
+
dots: {
|
|
4
|
+
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
|
|
5
|
+
interval: 80,
|
|
6
|
+
},
|
|
7
|
+
/** A slim vertical meter. */
|
|
8
|
+
meter: {
|
|
9
|
+
frames: ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'],
|
|
10
|
+
interval: 80,
|
|
11
|
+
},
|
|
12
|
+
/** Three-dot pulse. */
|
|
13
|
+
pulse: {
|
|
14
|
+
frames: ['·', '•', '●', '•'],
|
|
15
|
+
interval: 120,
|
|
16
|
+
},
|
|
17
|
+
/** ASCII fallback for terminals without unicode. */
|
|
18
|
+
ascii: {
|
|
19
|
+
frames: ['|', '/', '-', '\\'],
|
|
20
|
+
interval: 120,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export const defaultSpinner = spinnerStyles['dots'] ?? { frames: ['·'], interval: 100 };
|
|
24
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../src/frames.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,aAAa,GAAiC;IACzD,iDAAiD;IACjD,IAAI,EAAE;QACJ,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QAC1D,QAAQ,EAAE,EAAE;KACb;IACD,6BAA6B;IAC7B,KAAK,EAAE;QACL,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QAChD,QAAQ,EAAE,EAAE;KACb;IACD,uBAAuB;IACvB,KAAK,EAAE;QACL,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QAC5B,QAAQ,EAAE,GAAG;KACd;IACD,oDAAoD;IACpD,KAAK,EAAE;QACL,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC;QAC7B,QAAQ,EAAE,GAAG;KACd;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAiB,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { defaultSpinner, spinnerStyles, type SpinnerStyle } from './frames.js';
|
|
2
|
+
export { ProgressBar, type ProgressBarOptions } from './progress.js';
|
|
3
|
+
export { Spinner, type SpinnerOptions } from './spinner.js';
|
|
4
|
+
export { TaskRunner, type TaskRunnerOptions, type TaskSpec } from './tasks.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,WAAW,EAA2B,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,OAAO,EAAuB,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAyC,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface ProgressBarOptions {
|
|
2
|
+
total: number;
|
|
3
|
+
/** Bar width in cells. Default 30. */
|
|
4
|
+
width?: number;
|
|
5
|
+
stream?: {
|
|
6
|
+
write(data: string): unknown;
|
|
7
|
+
isTTY?: boolean;
|
|
8
|
+
};
|
|
9
|
+
unicode?: boolean;
|
|
10
|
+
label?: string;
|
|
11
|
+
showEta?: boolean;
|
|
12
|
+
style?: (text: string) => string;
|
|
13
|
+
/** Master switch — pass false for silent operation. */
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A single-line progress bar. `render()` is pure and stream-free so the UI
|
|
18
|
+
* layer (and tests) can compose it however they like.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ProgressBar {
|
|
21
|
+
value: number;
|
|
22
|
+
private readonly total;
|
|
23
|
+
private readonly width;
|
|
24
|
+
private readonly stream?;
|
|
25
|
+
private readonly unicode;
|
|
26
|
+
private readonly label?;
|
|
27
|
+
private readonly showEta;
|
|
28
|
+
private readonly style?;
|
|
29
|
+
private readonly enabled;
|
|
30
|
+
private readonly eta;
|
|
31
|
+
constructor(options: ProgressBarOptions);
|
|
32
|
+
/** Pure rendering of the current state. */
|
|
33
|
+
render(): string;
|
|
34
|
+
/** Advance to an absolute value and repaint. */
|
|
35
|
+
set(value: number): void;
|
|
36
|
+
/** Advance by a delta and repaint. */
|
|
37
|
+
inc(by?: number): void;
|
|
38
|
+
/** Finish: paint 100% and move to a new line. */
|
|
39
|
+
complete(): void;
|
|
40
|
+
private paint;
|
|
41
|
+
private etaText;
|
|
42
|
+
}
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single-line progress bar. `render()` is pure and stream-free so the UI
|
|
3
|
+
* layer (and tests) can compose it however they like.
|
|
4
|
+
*/
|
|
5
|
+
export class ProgressBar {
|
|
6
|
+
value = 0;
|
|
7
|
+
total;
|
|
8
|
+
width;
|
|
9
|
+
stream;
|
|
10
|
+
unicode;
|
|
11
|
+
label;
|
|
12
|
+
showEta;
|
|
13
|
+
style;
|
|
14
|
+
enabled;
|
|
15
|
+
eta;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.total = Math.max(1, options.total);
|
|
18
|
+
this.width = options.width ?? 30;
|
|
19
|
+
this.stream = options.stream;
|
|
20
|
+
this.unicode = options.unicode ?? true;
|
|
21
|
+
this.label = options.label;
|
|
22
|
+
this.showEta = options.showEta ?? false;
|
|
23
|
+
this.style = options.style;
|
|
24
|
+
this.enabled = options.enabled ?? this.stream?.isTTY === true;
|
|
25
|
+
this.eta = { startedAt: performance.now() };
|
|
26
|
+
}
|
|
27
|
+
/** Pure rendering of the current state. */
|
|
28
|
+
render() {
|
|
29
|
+
const clamped = Math.min(this.value, this.total);
|
|
30
|
+
const fraction = clamped / this.total;
|
|
31
|
+
const filled = Math.round(this.width * fraction);
|
|
32
|
+
const filledChar = this.unicode ? '█' : '#';
|
|
33
|
+
const emptyChar = this.unicode ? '░' : '-';
|
|
34
|
+
const bar = this.style ? this.style(filledChar.repeat(filled)) + emptyChar.repeat(this.width - filled) : `${filledChar.repeat(filled)}${emptyChar.repeat(this.width - filled)}`;
|
|
35
|
+
const parts = [`[${bar}]`, `${Math.round(fraction * 100)}%`, `${clamped}/${this.total}`];
|
|
36
|
+
if (this.label)
|
|
37
|
+
parts.push(this.label);
|
|
38
|
+
if (this.showEta) {
|
|
39
|
+
const etaText = this.etaText();
|
|
40
|
+
if (etaText)
|
|
41
|
+
parts.push(etaText);
|
|
42
|
+
}
|
|
43
|
+
return parts.join(' ');
|
|
44
|
+
}
|
|
45
|
+
/** Advance to an absolute value and repaint. */
|
|
46
|
+
set(value) {
|
|
47
|
+
this.value = Math.max(0, Math.min(value, this.total));
|
|
48
|
+
this.paint();
|
|
49
|
+
}
|
|
50
|
+
/** Advance by a delta and repaint. */
|
|
51
|
+
inc(by = 1) {
|
|
52
|
+
this.set(this.value + by);
|
|
53
|
+
}
|
|
54
|
+
/** Finish: paint 100% and move to a new line. */
|
|
55
|
+
complete() {
|
|
56
|
+
this.set(this.total);
|
|
57
|
+
if (this.enabled && this.stream) {
|
|
58
|
+
this.stream.write('\n');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
paint() {
|
|
62
|
+
if (this.enabled && this.stream) {
|
|
63
|
+
this.stream.write('\r\x1b[2K');
|
|
64
|
+
this.stream.write(this.render());
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
etaText() {
|
|
68
|
+
if (this.value <= 0)
|
|
69
|
+
return '';
|
|
70
|
+
const elapsed = performance.now() - this.eta.startedAt;
|
|
71
|
+
if (elapsed < 250)
|
|
72
|
+
return '';
|
|
73
|
+
const perItem = elapsed / this.value;
|
|
74
|
+
const remaining = (this.total - this.value) * perItem;
|
|
75
|
+
if (remaining < 1000)
|
|
76
|
+
return `eta <1s`;
|
|
77
|
+
return `eta ${Math.ceil(remaining / 1000)}s`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface SpinnerOptions {
|
|
2
|
+
/** Where output goes. Defaults to `process.stderr`. */
|
|
3
|
+
stream?: {
|
|
4
|
+
write(data: string): unknown;
|
|
5
|
+
};
|
|
6
|
+
/** Optional styling applied to the frame glyph (e.g. theme accent color). */
|
|
7
|
+
style?: (text: string) => string;
|
|
8
|
+
/** Frame name from `spinnerStyles`, or explicit frames. */
|
|
9
|
+
styleName?: string;
|
|
10
|
+
frames?: readonly string[];
|
|
11
|
+
/** Milliseconds per frame (overrides the named style's interval). */
|
|
12
|
+
interval?: number;
|
|
13
|
+
/** Render a static glyph instead of animating. */
|
|
14
|
+
reducedMotion?: boolean;
|
|
15
|
+
/** Master switch — pass false to disable all output. */
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* An animated spinner bound to a stream.
|
|
20
|
+
*
|
|
21
|
+
* - TTY + motion: animated frames, redrawn with `\r` + line clear.
|
|
22
|
+
* - Reduced motion or non-TTY: a single static line, no animation.
|
|
23
|
+
* - `with()` wraps async work: start → run → stop, error-safe.
|
|
24
|
+
*/
|
|
25
|
+
export declare class Spinner {
|
|
26
|
+
private readonly stream;
|
|
27
|
+
private readonly style?;
|
|
28
|
+
private readonly frames;
|
|
29
|
+
private readonly interval;
|
|
30
|
+
private readonly reducedMotion;
|
|
31
|
+
private readonly enabled;
|
|
32
|
+
private label;
|
|
33
|
+
private frame;
|
|
34
|
+
private timer;
|
|
35
|
+
private staticWritten;
|
|
36
|
+
constructor(options?: SpinnerOptions);
|
|
37
|
+
start(label: string): void;
|
|
38
|
+
/** Update the label while running (re-renders immediately). */
|
|
39
|
+
setLabel(label: string): void;
|
|
40
|
+
stop(finalLabel?: string): void;
|
|
41
|
+
/** Run `fn` under a spinner; always stops, even on error. */
|
|
42
|
+
with<T>(label: string, fn: () => Promise<T> | T): Promise<T>;
|
|
43
|
+
private renderFrame;
|
|
44
|
+
private writeLine;
|
|
45
|
+
}
|
package/dist/spinner.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { defaultSpinner, spinnerStyles } from './frames.js';
|
|
2
|
+
/**
|
|
3
|
+
* An animated spinner bound to a stream.
|
|
4
|
+
*
|
|
5
|
+
* - TTY + motion: animated frames, redrawn with `\r` + line clear.
|
|
6
|
+
* - Reduced motion or non-TTY: a single static line, no animation.
|
|
7
|
+
* - `with()` wraps async work: start → run → stop, error-safe.
|
|
8
|
+
*/
|
|
9
|
+
export class Spinner {
|
|
10
|
+
stream;
|
|
11
|
+
style;
|
|
12
|
+
frames;
|
|
13
|
+
interval;
|
|
14
|
+
reducedMotion;
|
|
15
|
+
enabled;
|
|
16
|
+
label = '';
|
|
17
|
+
frame = 0;
|
|
18
|
+
timer = null;
|
|
19
|
+
staticWritten = false;
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
const named = options.styleName ? spinnerStyles[options.styleName] : undefined;
|
|
22
|
+
this.stream = options.stream ?? process.stderr;
|
|
23
|
+
this.style = options.style;
|
|
24
|
+
this.frames = options.frames ?? named?.frames ?? defaultSpinner.frames;
|
|
25
|
+
this.interval = options.interval ?? named?.interval ?? defaultSpinner.interval;
|
|
26
|
+
this.reducedMotion = options.reducedMotion ?? false;
|
|
27
|
+
this.enabled = options.enabled ?? this.stream.isTTY === true;
|
|
28
|
+
}
|
|
29
|
+
start(label) {
|
|
30
|
+
this.label = label;
|
|
31
|
+
this.frame = 0;
|
|
32
|
+
if (!this.enabled)
|
|
33
|
+
return;
|
|
34
|
+
if (this.reducedMotion) {
|
|
35
|
+
this.writeLine(this.renderFrame());
|
|
36
|
+
this.staticWritten = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.writeLine(this.renderFrame());
|
|
40
|
+
this.timer = setInterval(() => {
|
|
41
|
+
this.frame = (this.frame + 1) % this.frames.length;
|
|
42
|
+
this.stream.write('\r\x1b[2K');
|
|
43
|
+
this.writeLine(this.renderFrame());
|
|
44
|
+
}, this.interval);
|
|
45
|
+
}
|
|
46
|
+
/** Update the label while running (re-renders immediately). */
|
|
47
|
+
setLabel(label) {
|
|
48
|
+
this.label = label;
|
|
49
|
+
if (this.timer) {
|
|
50
|
+
this.stream.write('\r\x1b[2K');
|
|
51
|
+
this.writeLine(this.renderFrame());
|
|
52
|
+
}
|
|
53
|
+
else if (this.enabled && this.staticWritten) {
|
|
54
|
+
this.stream.write('\r\x1b[2K');
|
|
55
|
+
this.writeLine(this.renderFrame());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
stop(finalLabel) {
|
|
59
|
+
if (this.timer) {
|
|
60
|
+
clearInterval(this.timer);
|
|
61
|
+
this.timer = null;
|
|
62
|
+
}
|
|
63
|
+
if (!this.enabled)
|
|
64
|
+
return;
|
|
65
|
+
this.stream.write('\r\x1b[2K');
|
|
66
|
+
if (finalLabel) {
|
|
67
|
+
this.stream.write(finalLabel + '\n');
|
|
68
|
+
}
|
|
69
|
+
this.staticWritten = false;
|
|
70
|
+
}
|
|
71
|
+
/** Run `fn` under a spinner; always stops, even on error. */
|
|
72
|
+
async with(label, fn) {
|
|
73
|
+
this.start(label);
|
|
74
|
+
try {
|
|
75
|
+
return await fn();
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
this.stop();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
renderFrame() {
|
|
82
|
+
const glyph = this.reducedMotion ? '·' : this.frames[this.frame % this.frames.length] ?? '·';
|
|
83
|
+
const frame = this.style ? this.style(glyph) : glyph;
|
|
84
|
+
return `${frame} ${this.label}`;
|
|
85
|
+
}
|
|
86
|
+
writeLine(line) {
|
|
87
|
+
this.stream.write(line);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../src/spinner.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface TaskSpec {
|
|
2
|
+
label: string;
|
|
3
|
+
fn: () => Promise<void> | void;
|
|
4
|
+
}
|
|
5
|
+
export interface TaskRunnerOptions {
|
|
6
|
+
stream?: {
|
|
7
|
+
write(data: string): unknown;
|
|
8
|
+
isTTY?: boolean;
|
|
9
|
+
};
|
|
10
|
+
unicode?: boolean;
|
|
11
|
+
reducedMotion?: boolean;
|
|
12
|
+
/** Cap on concurrent tasks. Default: run them all. */
|
|
13
|
+
concurrency?: number;
|
|
14
|
+
style?: (text: string) => string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Runs independent tasks concurrently with a live status line per task:
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
* • Building frontend
|
|
21
|
+
* ✓ Building backend 312ms
|
|
22
|
+
* ✗ Deploying staging (ECONNREFUSED)
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Mirrors the cargo/just-style parallel output. Non-TTY output degrades to
|
|
26
|
+
* one line per completed task.
|
|
27
|
+
*/
|
|
28
|
+
export declare class TaskRunner {
|
|
29
|
+
private readonly stream;
|
|
30
|
+
private readonly unicode;
|
|
31
|
+
private readonly style?;
|
|
32
|
+
private readonly live;
|
|
33
|
+
private readonly concurrency;
|
|
34
|
+
private lines;
|
|
35
|
+
private renderedCount;
|
|
36
|
+
constructor(options?: TaskRunnerOptions);
|
|
37
|
+
/** Run all tasks (optionally capped), updating status lines live. Returns the failure count. */
|
|
38
|
+
run(tasks: TaskSpec[]): Promise<number>;
|
|
39
|
+
private repaint;
|
|
40
|
+
private renderLine;
|
|
41
|
+
}
|
package/dist/tasks.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs independent tasks concurrently with a live status line per task:
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* • Building frontend
|
|
6
|
+
* ✓ Building backend 312ms
|
|
7
|
+
* ✗ Deploying staging (ECONNREFUSED)
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* Mirrors the cargo/just-style parallel output. Non-TTY output degrades to
|
|
11
|
+
* one line per completed task.
|
|
12
|
+
*/
|
|
13
|
+
export class TaskRunner {
|
|
14
|
+
stream;
|
|
15
|
+
unicode;
|
|
16
|
+
style;
|
|
17
|
+
live;
|
|
18
|
+
concurrency;
|
|
19
|
+
lines = [];
|
|
20
|
+
renderedCount = 0;
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this.stream = options.stream ?? process.stderr;
|
|
23
|
+
this.unicode = options.unicode ?? true;
|
|
24
|
+
this.style = options.style;
|
|
25
|
+
this.live = this.stream.isTTY === true && (options.reducedMotion ?? false) === false;
|
|
26
|
+
this.concurrency = options.concurrency ?? Number.POSITIVE_INFINITY;
|
|
27
|
+
}
|
|
28
|
+
/** Run all tasks (optionally capped), updating status lines live. Returns the failure count. */
|
|
29
|
+
async run(tasks) {
|
|
30
|
+
const limit = Math.min(this.concurrency, tasks.length);
|
|
31
|
+
let failures = 0;
|
|
32
|
+
let index = 0;
|
|
33
|
+
const launch = async () => {
|
|
34
|
+
while (index < tasks.length) {
|
|
35
|
+
const current = index++;
|
|
36
|
+
const spec = tasks[current];
|
|
37
|
+
const lineIndex = this.lines.length;
|
|
38
|
+
this.lines.push({ label: spec.label, state: 'running' });
|
|
39
|
+
this.repaint();
|
|
40
|
+
const taskIndex = lineIndex;
|
|
41
|
+
const startedAt = performance.now();
|
|
42
|
+
try {
|
|
43
|
+
await spec.fn();
|
|
44
|
+
this.lines[taskIndex].state = 'ok';
|
|
45
|
+
this.lines[taskIndex].ms = Math.max(1, Math.round(performance.now() - startedAt));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
this.lines[taskIndex].state = 'failed';
|
|
49
|
+
this.lines[taskIndex].ms = Math.max(1, Math.round(performance.now() - startedAt));
|
|
50
|
+
this.lines[taskIndex].error = error instanceof Error ? error.message : String(error);
|
|
51
|
+
failures++;
|
|
52
|
+
}
|
|
53
|
+
this.repaint();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
await Promise.all(Array.from({ length: Math.max(1, limit) }, () => launch()));
|
|
57
|
+
return failures;
|
|
58
|
+
}
|
|
59
|
+
repaint() {
|
|
60
|
+
if (!this.live) {
|
|
61
|
+
// Non-tty: emit each line as it completes (order may be out of sequence).
|
|
62
|
+
for (const line of this.lines) {
|
|
63
|
+
if (!line.emitted && line.state !== 'running') {
|
|
64
|
+
line.emitted = true;
|
|
65
|
+
this.stream.write(this.renderLine(line) + '\n');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (this.renderedCount > 0) {
|
|
71
|
+
this.stream.write(`\x1b[${this.renderedCount}A\x1b[J`);
|
|
72
|
+
}
|
|
73
|
+
for (const line of this.lines) {
|
|
74
|
+
this.stream.write(this.renderLine(line) + '\n');
|
|
75
|
+
}
|
|
76
|
+
this.renderedCount = this.lines.length;
|
|
77
|
+
}
|
|
78
|
+
renderLine(line) {
|
|
79
|
+
const mark = line.state === 'running' ? (this.unicode ? '•' : '*') : line.state === 'ok' ? (this.unicode ? '✓' : 'v') : this.unicode ? '✗' : 'x';
|
|
80
|
+
const glyph = this.style ? this.style(mark) : mark;
|
|
81
|
+
const parts = [` ${glyph} ${line.label}`];
|
|
82
|
+
if (line.state !== 'running' && line.ms !== undefined)
|
|
83
|
+
parts.push(`${line.ms}ms`);
|
|
84
|
+
if (line.state === 'failed' && line.error)
|
|
85
|
+
parts.push(`(${line.error})`);
|
|
86
|
+
return parts.join(' ');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mudah-cli/animation",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "60fps terminal animation engine: ticker, spinners, progress bars, task trees, and transitions.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=26"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@mudah-cli/terminal": "^0.1.0"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
}
|
|
26
|
+
}
|