@shoru/spindle 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aymane Shoru
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,239 @@
1
+ <div align="center">
2
+
3
+ # Spindle
4
+
5
+ A lightweight, singleton-based CLI multi-spinner library for Node.js. Run multiple spinners simultaneously without visual corruption, with automatic console interception.
6
+
7
+ [![Node.js](https://img.shields.io/badge/Node.js-18+-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org/)
8
+ [![Downloads](https://img.shields.io/npm/d18m/@shoru/spindle.svg?style=for-the-badge)](https://www.npmjs.com/package/@shoru/spindle)
9
+ [![npm](https://img.shields.io/npm/v/@shoru/spindle.svg?style=for-the-badge)](https://www.npmjs.com/package/@shoru/spindle)
10
+ [![Types](https://img.shields.io/badge/types-included-blue?style=for-the-badge&logo=typescript)](https://github.com/Mangaka-bot/spindle/tree/main/src)
11
+
12
+ [Installation](#-installation) · [Quick Start](#-quick-start) · [API](#-api)
13
+
14
+ </div>
15
+
16
+ ---
17
+
18
+ ## ✨ Features
19
+
20
+ - 🔄 **Multiple Concurrent Spinners** - Run as many spinners as you need
21
+ - 🎨 **Customizable Colors** - 17 color options for spinner customization
22
+ - 📝 **Console Interception** - `console.log` and friends work seamlessly without breaking spinners
23
+ - ✨ **Final States** - Complete spinners with success, failure, warning, or info icons
24
+ - 🧹 **Automatic Cleanup** - Graceful handling of process exit, SIGINT, and SIGTERM
25
+ - 📦 **Singleton Architecture** - Centralized render management for flicker-free output
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install @shoru/spindle
31
+ ```
32
+
33
+ </div>
34
+
35
+ ---
36
+
37
+ ## 📦 Installation
38
+
39
+ ```bash
40
+ npm install @shoru/spindle
41
+ ```
42
+
43
+ > Requires Node.js 18+
44
+
45
+ ---
46
+
47
+ ## Quick Start
48
+
49
+ ```javascript
50
+ import { spindle } from '@shoru/spindle';
51
+
52
+ const spinner = spindle('Loading...').start();
53
+
54
+ // Do some async work
55
+ await someAsyncTask();
56
+
57
+ spinner.succeed('Done!');
58
+ ```
59
+
60
+ ## API
61
+
62
+ ### Creating a Spindle
63
+
64
+ ```javascript
65
+ import { spindle, Spindle } from '@shoru/spindle';
66
+
67
+ // Using factory function (recommended)
68
+ const spinner = spindle('Initial text');
69
+
70
+ // Using constructor
71
+ const spinner = new Spindle('Initial text');
72
+ ```
73
+
74
+ ### Methods
75
+
76
+ #### `.start(text?)`
77
+
78
+ Starts the spinner. Optionally updates the text.
79
+
80
+ ```javascript
81
+ spinner.start();
82
+ spinner.start('New loading message...');
83
+ ```
84
+
85
+ #### `.stop()`
86
+
87
+ Stops the spinner without displaying a final message.
88
+
89
+ ```javascript
90
+ spinner.stop();
91
+ ```
92
+
93
+ #### `.succeed(text?)`
94
+
95
+ Stops with a green checkmark (✔).
96
+
97
+ ```javascript
98
+ spinner.succeed('Task completed successfully');
99
+ ```
100
+
101
+ #### `.fail(text?)`
102
+
103
+ Stops with a red cross (✖).
104
+
105
+ ```javascript
106
+ spinner.fail('Task failed');
107
+ ```
108
+
109
+ #### `.warn(text?)`
110
+
111
+ Stops with a yellow warning sign (⚠).
112
+
113
+ ```javascript
114
+ spinner.warn('Task completed with warnings');
115
+ ```
116
+
117
+ #### `.info(text?)`
118
+
119
+ Stops with a blue info icon (ℹ).
120
+
121
+ ```javascript
122
+ spinner.info('Additional information');
123
+ ```
124
+
125
+ ### Properties
126
+
127
+ #### `.text` / `.title`
128
+
129
+ Get or set the spinner text. Both properties are interchangeable.
130
+
131
+ ```javascript
132
+ spinner.text = 'Downloading files...';
133
+ console.log(spinner.text); // 'Downloading files...'
134
+ ```
135
+
136
+ #### `.color`
137
+
138
+ Get or set the spinner color.
139
+
140
+ ```javascript
141
+ spinner.color = 'magenta';
142
+ ```
143
+
144
+ #### `.isSpinning`
145
+
146
+ Check if the spinner is currently active.
147
+
148
+ ```javascript
149
+ if (spinner.isSpinning) {
150
+ spinner.succeed('Finished');
151
+ }
152
+ ```
153
+
154
+ ### Available Colors
155
+
156
+ | Standard | Bright |
157
+ |----------|--------|
158
+ | `black` | `gray`/`grey` |
159
+ | `red` | `redBright` |
160
+ | `green` | `greenBright` |
161
+ | `yellow` | `yellowBright` |
162
+ | `blue` | `blueBright` |
163
+ | `magenta` | `magentaBright` |
164
+ | `cyan` | `cyanBright` |
165
+ | `white` | `whiteBright` |
166
+
167
+ > Default: `cyan`
168
+
169
+ ### RendererManager
170
+
171
+ The `RendererManager` singleton coordinates all active spinners. You typically don't need to interact with it directly, but it's available for advanced use cases.
172
+
173
+ ```javascript
174
+ import { RendererManager } from '@shoru/spindle';
175
+
176
+ // Check if any spinners are active
177
+ if (RendererManager.isActive()) {
178
+ console.log('Spinners are running');
179
+ }
180
+
181
+ // Get count of active spinners
182
+ const count = RendererManager.getActiveCount();
183
+
184
+ // Force reset all spinners (use with caution)
185
+ RendererManager.reset(true);
186
+ ```
187
+
188
+ ## TypeScript Support
189
+
190
+ Full TypeScript support with exported types:
191
+
192
+ ```typescript
193
+ import {
194
+ Spindle,
195
+ spindle,
196
+ SpinnerColor,
197
+ FinalState,
198
+ TaskState,
199
+ Renderable
200
+ } from '@shoru/spindle';
201
+
202
+ const color: SpinnerColor = 'cyan';
203
+ const state: FinalState = 'completed';
204
+ ```
205
+
206
+ ## How It Works
207
+
208
+ 1. **Singleton Renderer**: A single `RendererManager` coordinates all spinner instances
209
+ 2. **Console Interception**: When spinners are active, console methods are intercepted and buffered
210
+ 3. **Unified Rendering**: All spinners render to a single output using `log-update`
211
+ 4. **Clean Output**: Buffered logs are flushed above the spinner display
212
+ 5. **Graceful Cleanup**: Process signals trigger proper cleanup to restore console state
213
+
214
+ ---
215
+
216
+ ## 🤝 Contributing
217
+
218
+ Contributions are welcome! Please feel free to submit a Pull Request.
219
+
220
+ 1. Fork the repository
221
+ 2. Create feature branch `git checkout -b feature/amazing-feature`
222
+ 3. Commit changes `git commit -m 'Add amazing feature'`
223
+ 4. Push `git push origin feature/amazing-feature`
224
+ 5. Open Pull Request
225
+
226
+ ---
227
+
228
+ <div align="center">
229
+
230
+ [![License](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](LICENSE)
231
+ <br>
232
+ This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
233
+
234
+ <br>
235
+
236
+ **Made with ❤️ for the Node.js CLI community**
237
+
238
+ [⬆ Back to Top](#-spindle)
239
+ </div>
@@ -0,0 +1,7 @@
1
+ import type { SpinnerColor, StateConfig, FinalState } from './types.js';
2
+ export declare const SPINNER_FRAMES: readonly ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
3
+ export declare const SPINNER_INTERVAL: 80;
4
+ export declare const DEFAULT_COLOR: SpinnerColor;
5
+ export declare const VALID_COLORS: ReadonlySet<string>;
6
+ export declare const STATE_CONFIG: Readonly<Record<FinalState | 'default', StateConfig>>;
7
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExE,eAAO,MAAM,cAAc,6DAEjB,CAAC;AAEX,eAAO,MAAM,gBAAgB,EAAG,EAAW,CAAC;AAC5C,eAAO,MAAM,aAAa,EAAE,YAAqB,CAAC;AAElD,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,CAI3C,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,GAAG,SAAS,EAAE,WAAW,CAAC,CAM9E,CAAC"}
@@ -0,0 +1,18 @@
1
+ export const SPINNER_FRAMES = [
2
+ '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'
3
+ ];
4
+ export const SPINNER_INTERVAL = 80;
5
+ export const DEFAULT_COLOR = 'cyan';
6
+ export const VALID_COLORS = new Set([
7
+ 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
8
+ 'gray', 'grey', 'redBright', 'greenBright', 'yellowBright', 'blueBright',
9
+ 'magentaBright', 'cyanBright', 'whiteBright'
10
+ ]);
11
+ export const STATE_CONFIG = {
12
+ completed: { icon: '✔', iconColor: 'green', textColor: 'white' },
13
+ failed: { icon: '✖', iconColor: 'red', textColor: 'red' },
14
+ warning: { icon: '⚠', iconColor: 'yellow', textColor: 'yellow' },
15
+ info: { icon: 'ℹ', iconColor: 'blue', textColor: 'blue' },
16
+ default: { icon: '○', iconColor: 'gray', textColor: 'white' }
17
+ };
18
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CACxC,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAW,CAAC;AAC5C,MAAM,CAAC,MAAM,aAAa,GAAiB,MAAM,CAAC;AAElD,MAAM,CAAC,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAe;IACrE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO;IACrE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY;IACxE,eAAe,EAAE,YAAY,EAAE,aAAa;CAC7C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAA0D;IACjF,SAAS,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAG,SAAS,EAAE,OAAO,EAAG;IAClE,MAAM,EAAK,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAK,SAAS,EAAE,KAAK,EAAK;IAClE,OAAO,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE;IAClE,IAAI,EAAO,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAI,SAAS,EAAE,MAAM,EAAI;IAClE,OAAO,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAI,SAAS,EAAE,OAAO,EAAG;CACnE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { SpinnerColor, FinalState, StateFormatters } from './types.js';
2
+ type ChalkFn = (text: string) => string;
3
+ export declare const getChalkColor: (color: SpinnerColor) => ChalkFn;
4
+ export declare const getStateFormatters: (state: FinalState) => StateFormatters;
5
+ export {};
6
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE5E,KAAK,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAKxC,eAAO,MAAM,aAAa,GAAI,OAAO,YAAY,KAAG,OACS,CAAC;AAE9D,eAAO,MAAM,kBAAkB,GAAI,OAAO,UAAU,KAAG,eAStD,CAAC"}
@@ -0,0 +1,14 @@
1
+ import chalk from 'chalk';
2
+ import { VALID_COLORS, DEFAULT_COLOR, STATE_CONFIG } from './constants.js';
3
+ const getColorFn = (color) => chalk[color];
4
+ export const getChalkColor = (color) => getColorFn(VALID_COLORS.has(color) ? color : DEFAULT_COLOR);
5
+ export const getStateFormatters = (state) => {
6
+ const config = STATE_CONFIG[state] ?? STATE_CONFIG.default;
7
+ const iconFn = getColorFn(config.iconColor);
8
+ const textFn = getColorFn(config.textColor);
9
+ return {
10
+ icon: iconFn(config.icon),
11
+ text: textFn
12
+ };
13
+ };
14
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAK3E,MAAM,UAAU,GAAG,CAAC,KAAmB,EAAW,EAAE,CAClD,KAAK,CAAC,KAAK,CAAY,CAAC;AAE1B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAmB,EAAW,EAAE,CAC5D,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAiB,EAAmB,EAAE;IACvE,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC;IAC3D,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAE5C,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;QACzB,IAAI,EAAE,MAAM;KACb,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { SpinnerColor, Renderable } from './types.js';
2
+ export type { SpinnerColor, FinalState, TaskState, TaskConfig, Renderable } from './types.js';
3
+ export { RendererManager } from './renderer-manager.js';
4
+ export declare class Spindle implements Renderable {
5
+ #private;
6
+ constructor(text?: string);
7
+ start(text?: string): this;
8
+ stop(): this;
9
+ succeed(text?: string): this;
10
+ fail(text?: string): this;
11
+ warn(text?: string): this;
12
+ info(text?: string): this;
13
+ get text(): string;
14
+ set text(value: string);
15
+ get title(): string;
16
+ set title(value: string);
17
+ get color(): SpinnerColor;
18
+ set color(value: SpinnerColor);
19
+ get isSpinning(): boolean;
20
+ renderToString(): string;
21
+ }
22
+ export declare function spindle(text?: string): Spindle;
23
+ export default Spindle;
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAc,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,qBAAa,OAAQ,YAAW,UAAU;;gBAO5B,IAAI,SAAK;IAIrB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAW1B,IAAI,IAAI,IAAI;IASZ,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAC5B,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IACzB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IACzB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IA0BzB,IAAI,IAAI,IAAI,MAAM,CAAuB;IACzC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAGrB;IAED,IAAI,KAAK,IAAI,MAAM,CAAuB;IAC1C,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAAwB;IAE/C,IAAI,KAAK,IAAI,YAAY,CAAwB;IACjD,IAAI,KAAK,CAAC,KAAK,EAAE,YAAY,EAG5B;IAED,IAAI,UAAU,IAAI,OAAO,CAA2B;IAEpD,cAAc,IAAI,MAAM;CAMzB;AAED,wBAAgB,OAAO,CAAC,IAAI,SAAK,GAAG,OAAO,CAE1C;AAED,eAAe,OAAO,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,80 @@
1
+ import chalk from 'chalk';
2
+ import { RendererManager } from './renderer-manager.js';
3
+ import { getChalkColor, getStateFormatters } from './helpers.js';
4
+ export { RendererManager } from './renderer-manager.js';
5
+ export class Spindle {
6
+ #text;
7
+ #color = 'cyan';
8
+ #isActive = false;
9
+ #finalState = null;
10
+ #manager = null;
11
+ constructor(text = '') {
12
+ this.#text = text;
13
+ }
14
+ start(text) {
15
+ if (text !== undefined)
16
+ this.#text = text;
17
+ if (this.#isActive)
18
+ return this;
19
+ this.#isActive = true;
20
+ this.#finalState = null;
21
+ this.#manager = RendererManager.getInstance();
22
+ this.#manager.register(this);
23
+ return this;
24
+ }
25
+ stop() {
26
+ if (!this.#isActive)
27
+ return this;
28
+ this.#isActive = false;
29
+ this.#manager?.unregister(this);
30
+ this.#manager = null;
31
+ return this;
32
+ }
33
+ succeed(text) { return this.#complete('completed', text); }
34
+ fail(text) { return this.#complete('failed', text); }
35
+ warn(text) { return this.#complete('warning', text); }
36
+ info(text) { return this.#complete('info', text); }
37
+ #complete(state, text) {
38
+ this.#finalState = state;
39
+ const finalText = text ?? this.#text;
40
+ const { icon, text: colorText } = getStateFormatters(state);
41
+ const line = `${icon} ${colorText(finalText)}`;
42
+ if (!this.#isActive) {
43
+ console.log(line);
44
+ return this;
45
+ }
46
+ this.#isActive = false;
47
+ this.#manager?.scheduleRender();
48
+ setImmediate(() => {
49
+ console.log(line);
50
+ this.#manager?.unregister(this);
51
+ this.#manager = null;
52
+ this.#finalState = null;
53
+ });
54
+ return this;
55
+ }
56
+ get text() { return this.#text; }
57
+ set text(value) {
58
+ this.#text = value;
59
+ this.#manager?.scheduleRender();
60
+ }
61
+ get title() { return this.#text; }
62
+ set title(value) { this.text = value; }
63
+ get color() { return this.#color; }
64
+ set color(value) {
65
+ this.#color = value;
66
+ this.#manager?.scheduleRender();
67
+ }
68
+ get isSpinning() { return this.#isActive; }
69
+ renderToString() {
70
+ if (this.#finalState)
71
+ return '';
72
+ const frame = RendererManager.getInstance().getSpinnerFrame();
73
+ return `${getChalkColor(this.#color)(frame)} ${chalk.white(this.#text)}`;
74
+ }
75
+ }
76
+ export function spindle(text = '') {
77
+ return new Spindle(text);
78
+ }
79
+ export default Spindle;
80
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Renderable } from './types.js';
2
+ export declare class RendererManager {
3
+ #private;
4
+ private constructor();
5
+ static getInstance(): RendererManager;
6
+ static isActive(): boolean;
7
+ static getActiveCount(): number;
8
+ static reset(force?: boolean): void;
9
+ get isDisposed(): boolean;
10
+ getSpinnerFrame(): string;
11
+ register(renderer: Renderable): void;
12
+ unregister(renderer: Renderable): void;
13
+ scheduleRender(): void;
14
+ dispose(): void;
15
+ }
16
+ //# sourceMappingURL=renderer-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-manager.d.ts","sourceRoot":"","sources":["../src/renderer-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAuC,MAAM,YAAY,CAAC;AAclF,qBAAa,eAAe;;IAe1B,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,eAAe;IASrC,MAAM,CAAC,QAAQ,IAAI,OAAO;IAK1B,MAAM,CAAC,cAAc,IAAI,MAAM;IAK/B,MAAM,CAAC,KAAK,CAAC,KAAK,UAAQ,GAAG,IAAI;IAejC,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,eAAe,IAAI,MAAM;IAKzB,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAUpC,UAAU,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI;IAYtC,cAAc,IAAI,IAAI;IAWtB,OAAO,IAAI,IAAI;CA4KhB"}
@@ -0,0 +1,252 @@
1
+ import logUpdate from 'log-update';
2
+ import { SPINNER_FRAMES, SPINNER_INTERVAL } from './constants.js';
3
+ const CONSOLE_METHODS = {
4
+ log: 'stdout', info: 'stdout', debug: 'stdout', warn: 'stderr', error: 'stderr'
5
+ };
6
+ const CONSOLE_METHOD_KEYS = Object.keys(CONSOLE_METHODS);
7
+ // Default frame as fallback (satisfies noUncheckedIndexedAccess)
8
+ const DEFAULT_FRAME = '⠋';
9
+ export class RendererManager {
10
+ static #instance = null;
11
+ #activeRenderers = new Set();
12
+ #originalConsole = {};
13
+ #originalStdoutWrite = null;
14
+ #originalStderrWrite = null;
15
+ #logBuffer = [];
16
+ #isInternalWrite = false;
17
+ #intercepted = false;
18
+ #renderScheduled = false;
19
+ #spinnerIndex = 0;
20
+ #spinnerInterval = null;
21
+ #isDisposed = false;
22
+ constructor() { }
23
+ static getInstance() {
24
+ let inst = RendererManager.#instance;
25
+ if (!inst || inst.#isDisposed) {
26
+ inst = new RendererManager();
27
+ RendererManager.#instance = inst;
28
+ }
29
+ return inst;
30
+ }
31
+ static isActive() {
32
+ const inst = RendererManager.#instance;
33
+ return Boolean(inst && !inst.#isDisposed && inst.#activeRenderers.size);
34
+ }
35
+ static getActiveCount() {
36
+ const inst = RendererManager.#instance;
37
+ return inst && !inst.#isDisposed ? inst.#activeRenderers.size : 0;
38
+ }
39
+ static reset(force = false) {
40
+ const inst = RendererManager.#instance;
41
+ if (!inst)
42
+ return;
43
+ if (!force && inst.#activeRenderers.size > 0) {
44
+ console.warn(`RendererManager: ${inst.#activeRenderers.size} active renderers. Use reset(true) to force.`);
45
+ return;
46
+ }
47
+ inst.dispose();
48
+ RendererManager.#instance = null;
49
+ }
50
+ get isDisposed() {
51
+ return this.#isDisposed;
52
+ }
53
+ getSpinnerFrame() {
54
+ // FIX 1: Provide fallback for noUncheckedIndexedAccess
55
+ return SPINNER_FRAMES[this.#spinnerIndex] ?? DEFAULT_FRAME;
56
+ }
57
+ register(renderer) {
58
+ if (this.#isDisposed)
59
+ throw new Error('RendererManager disposed');
60
+ const wasEmpty = this.#activeRenderers.size === 0;
61
+ this.#activeRenderers.add(renderer);
62
+ if (wasEmpty)
63
+ this.#startManaging();
64
+ this.scheduleRender();
65
+ }
66
+ unregister(renderer) {
67
+ if (this.#isDisposed)
68
+ return;
69
+ this.#activeRenderers.delete(renderer);
70
+ if (this.#activeRenderers.size === 0) {
71
+ this.#stopManaging();
72
+ }
73
+ else {
74
+ this.scheduleRender();
75
+ }
76
+ }
77
+ scheduleRender() {
78
+ if (this.#isDisposed || this.#renderScheduled || !this.#activeRenderers.size)
79
+ return;
80
+ this.#renderScheduled = true;
81
+ setImmediate(() => {
82
+ if (this.#isDisposed)
83
+ return;
84
+ this.#renderScheduled = false;
85
+ this.#render();
86
+ });
87
+ }
88
+ dispose() {
89
+ if (this.#isDisposed)
90
+ return;
91
+ this.#isDisposed = true;
92
+ this.#stopManaging();
93
+ this.#activeRenderers.clear();
94
+ this.#logBuffer.length = 0;
95
+ }
96
+ #startManaging() {
97
+ if (this.#intercepted || this.#isDisposed)
98
+ return;
99
+ this.#interceptConsole();
100
+ this.#interceptStreams();
101
+ this.#intercepted = true;
102
+ this.#spinnerInterval = setInterval(() => {
103
+ if (this.#isDisposed)
104
+ return this.#stopManaging();
105
+ this.#spinnerIndex = (this.#spinnerIndex + 1) % SPINNER_FRAMES.length;
106
+ this.#render();
107
+ }, SPINNER_INTERVAL);
108
+ this.#spinnerInterval.unref?.();
109
+ }
110
+ #stopManaging() {
111
+ this.#flushLogBuffer();
112
+ if (this.#spinnerInterval) {
113
+ clearInterval(this.#spinnerInterval);
114
+ this.#spinnerInterval = null;
115
+ }
116
+ if (this.#intercepted) {
117
+ this.#restoreConsole();
118
+ this.#restoreStreams();
119
+ this.#intercepted = false;
120
+ try {
121
+ logUpdate.done();
122
+ }
123
+ catch { /* noop */ }
124
+ }
125
+ this.#spinnerIndex = 0;
126
+ }
127
+ #render() {
128
+ if (this.#isDisposed || !this.#activeRenderers.size)
129
+ return;
130
+ this.#flushLogBuffer();
131
+ const outputs = [];
132
+ for (const renderer of this.#activeRenderers) {
133
+ try {
134
+ const output = renderer.renderToString();
135
+ if (output)
136
+ outputs.push(output);
137
+ }
138
+ catch { /* noop */ }
139
+ }
140
+ if (outputs.length) {
141
+ this.#internalWrite(() => logUpdate(outputs.join('\n\n')));
142
+ }
143
+ }
144
+ #interceptConsole() {
145
+ for (const method of CONSOLE_METHOD_KEYS) {
146
+ const stream = CONSOLE_METHODS[method];
147
+ this.#originalConsole[method] = console[method].bind(console);
148
+ console[method] = (...args) => {
149
+ if (this.#isDisposed) {
150
+ this.#originalConsole[method]?.(...args);
151
+ return;
152
+ }
153
+ this.#logBuffer.push({ method, args, stream });
154
+ this.scheduleRender();
155
+ };
156
+ }
157
+ }
158
+ #interceptStreams() {
159
+ this.#originalStdoutWrite = process.stdout.write.bind(process.stdout);
160
+ this.#originalStderrWrite = process.stderr.write.bind(process.stderr);
161
+ const createInterceptor = (stream, original) => {
162
+ return ((chunk, encodingOrCb, callback) => {
163
+ if (this.#isInternalWrite || this.#isDisposed) {
164
+ return original.call(stream === 'stdout' ? process.stdout : process.stderr, chunk, encodingOrCb, callback);
165
+ }
166
+ const encoding = typeof encodingOrCb === 'string' ? encodingOrCb : 'utf8';
167
+ const cb = typeof encodingOrCb === 'function' ? encodingOrCb : callback;
168
+ // FIX 2: Uint8Array.toString() takes no arguments
169
+ // Use Buffer.from() or TextDecoder for proper encoding support
170
+ let str;
171
+ if (typeof chunk === 'string') {
172
+ str = chunk;
173
+ }
174
+ else {
175
+ // Convert Uint8Array to string with proper encoding
176
+ str = Buffer.from(chunk).toString(encoding);
177
+ }
178
+ if (str.trim()) {
179
+ this.#logBuffer.push({ method: 'raw', args: [str], stream });
180
+ this.scheduleRender();
181
+ }
182
+ cb?.();
183
+ return true;
184
+ });
185
+ };
186
+ process.stdout.write = createInterceptor('stdout', this.#originalStdoutWrite);
187
+ process.stderr.write = createInterceptor('stderr', this.#originalStderrWrite);
188
+ }
189
+ #restoreConsole() {
190
+ for (const method of CONSOLE_METHOD_KEYS) {
191
+ const fn = this.#originalConsole[method];
192
+ if (fn)
193
+ console[method] = fn;
194
+ }
195
+ this.#originalConsole = {};
196
+ }
197
+ #restoreStreams() {
198
+ if (this.#originalStdoutWrite)
199
+ process.stdout.write = this.#originalStdoutWrite;
200
+ if (this.#originalStderrWrite)
201
+ process.stderr.write = this.#originalStderrWrite;
202
+ this.#originalStdoutWrite = null;
203
+ this.#originalStderrWrite = null;
204
+ }
205
+ #flushLogBuffer() {
206
+ if (!this.#logBuffer.length)
207
+ return;
208
+ const buffer = this.#logBuffer.splice(0);
209
+ this.#internalWrite(() => { try {
210
+ logUpdate.clear();
211
+ }
212
+ catch { /* noop */ } });
213
+ for (const { method, args, stream } of buffer) {
214
+ this.#internalWrite(() => {
215
+ try {
216
+ if (method === 'raw') {
217
+ const writer = stream === 'stderr'
218
+ ? this.#originalStderrWrite
219
+ : this.#originalStdoutWrite;
220
+ // Safe access with type guard
221
+ const text = args[0];
222
+ if (writer && typeof text === 'string') {
223
+ const output = text.endsWith('\n') ? text : `${text}\n`;
224
+ writer.call(stream === 'stderr' ? process.stderr : process.stdout, output);
225
+ }
226
+ }
227
+ else {
228
+ this.#originalConsole[method]?.(...args);
229
+ }
230
+ }
231
+ catch { /* noop */ }
232
+ });
233
+ }
234
+ }
235
+ #internalWrite(fn) {
236
+ this.#isInternalWrite = true;
237
+ try {
238
+ fn();
239
+ }
240
+ finally {
241
+ this.#isInternalWrite = false;
242
+ }
243
+ }
244
+ }
245
+ // Process cleanup handlers
246
+ if (typeof process !== 'undefined') {
247
+ const cleanup = () => RendererManager.reset(true);
248
+ process.once('exit', cleanup);
249
+ process.once('SIGINT', () => { cleanup(); process.exit(130); });
250
+ process.once('SIGTERM', () => { cleanup(); process.exit(143); });
251
+ }
252
+ //# sourceMappingURL=renderer-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-manager.js","sourceRoot":"","sources":["../src/renderer-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ export type SpinnerColor = 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray' | 'grey' | 'redBright' | 'greenBright' | 'yellowBright' | 'blueBright' | 'magentaBright' | 'cyanBright' | 'whiteBright';
2
+ export type FinalState = 'completed' | 'failed' | 'warning' | 'info';
3
+ export type TaskState = 'pending' | 'processing' | 'skipped' | FinalState;
4
+ export type ExecutionType = 'initial' | 'auto' | 'retry';
5
+ export type ConsoleMethod = 'log' | 'info' | 'debug' | 'warn' | 'error';
6
+ export type StreamType = 'stdout' | 'stderr';
7
+ export interface StateConfig {
8
+ readonly icon: string;
9
+ readonly iconColor: SpinnerColor;
10
+ readonly textColor: SpinnerColor;
11
+ }
12
+ export interface StateFormatters {
13
+ readonly icon: string;
14
+ readonly text: (t: string) => string;
15
+ }
16
+ export interface Renderable {
17
+ renderToString(): string;
18
+ }
19
+ export interface LogEntry {
20
+ readonly method: ConsoleMethod | 'raw';
21
+ readonly args: readonly unknown[];
22
+ readonly stream: StreamType;
23
+ }
24
+ export interface TaskNode {
25
+ title: string;
26
+ state: TaskState;
27
+ }
28
+ export interface RetryConfig {
29
+ readonly tries: number;
30
+ readonly delay?: number;
31
+ }
32
+ export interface RendererOptions {
33
+ readonly renderer?: 'default' | 'simple' | 'silent';
34
+ }
35
+ export interface TaskOptions {
36
+ readonly concurrent?: boolean;
37
+ readonly exitOnError?: boolean;
38
+ }
39
+ export interface TaskConfig {
40
+ readonly title: string;
41
+ readonly setup?: (ctx: Record<string, unknown>, task: TaskNode) => Promise<unknown>;
42
+ readonly task?: (ctx: Record<string, unknown>, task: TaskNode, type: ExecutionType) => Promise<unknown>;
43
+ readonly afterEach?: (ctx: Record<string, unknown>, completedSubtask: TaskNode, mainTask: TaskNode) => Promise<void>;
44
+ readonly finally?: (ctx: Record<string, unknown>, task: TaskNode) => Promise<void>;
45
+ readonly options?: TaskOptions;
46
+ readonly autoExecute?: number;
47
+ readonly autoComplete?: number;
48
+ readonly rollback?: (ctx: Record<string, unknown>, task: TaskNode) => Promise<void>;
49
+ readonly skip?: (ctx: Record<string, unknown>) => boolean | string;
50
+ readonly retry?: RetryConfig;
51
+ readonly showTimer?: boolean;
52
+ readonly batchDebounceMs?: number;
53
+ readonly defaultSubtaskOptions?: Record<string, unknown>;
54
+ readonly rendererOptions?: RendererOptions;
55
+ readonly spinnerColor?: SpinnerColor;
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@shoru/spindle",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight, singleton-based CLI multi-spinner library for Node.js",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "repository": {
8
+ "url": "git+https://github.com/Mangaka-bot/ListrX.git"
9
+ },
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [ "dist" ],
18
+ "keywords": [
19
+ "cli",
20
+ "console",
21
+ "terminal",
22
+ "task",
23
+ "listr",
24
+ "listr2",
25
+ "spinner",
26
+ "ora",
27
+ "loader",
28
+ "progress",
29
+ "subtask",
30
+ "async",
31
+ "concurrent",
32
+ "workflow",
33
+ "pipeline",
34
+ "task-runner",
35
+ "command-line",
36
+ "log-update",
37
+ "animation",
38
+ "tree",
39
+ "rxjs",
40
+ "chalk",
41
+ "interactive",
42
+ "dynamic",
43
+ "retry",
44
+ "rollback",
45
+ "automation"
46
+ ],
47
+ "author": "Shoru",
48
+ "license": "MIT",
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "typescript": "^5.9.3"
54
+ },
55
+ "scripts": {
56
+ "build": "tsc"
57
+ },
58
+ "dependencies": {
59
+ "chalk": "^5.6.2",
60
+ "log-update": "^7.0.2",
61
+ "rxjs": "^7.8.2"
62
+ }
63
+ }