Skip to content

Commit 601fd85

Browse files
committed
Update yocto spinner
1 parent bbe3629 commit 601fd85

File tree

2 files changed

+129
-134
lines changed

2 files changed

+129
-134
lines changed

packages/npm/yocto-spinner/index.cjs

Lines changed: 128 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -102,223 +102,218 @@ function stripVTControlCharacters(string) {
102102
}
103103

104104
class YoctoSpinner {
105-
#color
106-
#currentFrame = -1
107-
#exitHandlerBound
108105
#frames
109-
#indention = ''
110106
#interval
107+
#currentFrame = -1
108+
#timer
109+
#text
110+
#stream
111+
#color
112+
#lines = 0
113+
#exitHandlerBound
111114
#isInteractive
112115
#lastSpinnerFrameTime = 0
113-
#lines = 0
114-
#signal
115-
#stream
116-
#text
117-
#timer
116+
#isSpinning = false
118117

119118
constructor(options = {}) {
120119
const opts = { __proto__: null, ...options }
121120
const spinner = opts.spinner ?? getDefaultSpinner()
122121
const stream = opts.stream ?? getProcess().stderr
123-
this.#color = opts.color ?? 'cyan'
124-
this.#exitHandlerBound = this.#exitHandler.bind(this)
125122
this.#frames = spinner.frames
126-
this.#interval = spinner.interval ?? getDefaultSpinner().interval
123+
this.#interval = spinner.interval
124+
this.#text = options.text ?? ''
125+
this.#stream = stream ?? process.stderr
126+
this.#color = options.color ?? 'cyan'
127127
this.#isInteractive = !!stream.isTTY && isProcessInteractive()
128-
this.#signal = opts.signal
129-
this.#stream = stream
130-
this.#text = opts.text ?? ''
128+
this.#exitHandlerBound = this.#exitHandler.bind(this)
131129
}
132130

133-
#clearTimer() {
134-
clearInterval(this.#timer)
135-
this.#timer = undefined
136-
}
131+
start(text) {
132+
if (text) {
133+
this.#text = text
134+
}
137135

138-
#exitHandler() {
139136
if (this.isSpinning) {
140-
this.stop()
137+
return this
141138
}
142-
}
143139

144-
#hideCursor() {
140+
this.#isSpinning = true
141+
this.#hideCursor()
142+
this.#render()
143+
this.#subscribeToProcessEvents()
144+
145+
// Only start the timer in interactive mode
145146
if (this.#isInteractive) {
146-
this.#write('\u001B[?25l')
147+
this.#timer = setInterval(() => {
148+
this.#render()
149+
}, this.#interval)
147150
}
148-
}
149151

150-
#lineCount(text) {
151-
const width = this.#stream.columns ?? defaultTtyColumns
152-
const lines = stripVTControlCharacters(text).split('\n')
153-
let lineCount = 0
154-
for (const line of lines) {
155-
lineCount += Math.max(1, Math.ceil(line.length / width))
156-
}
157-
return lineCount
152+
return this
158153
}
159154

160-
#render() {
161-
// Ensure we only update the spinner frame at the wanted interval,
162-
// even if the frame method is called more often.
163-
const now = Date.now()
164-
if (
165-
this.#currentFrame === -1 ||
166-
now - this.#lastSpinnerFrameTime >= this.#interval
167-
) {
168-
this.#currentFrame = (this.#currentFrame + 1) % this.#frames.length
169-
this.#lastSpinnerFrameTime = now
170-
}
171-
const colors = getYoctocolors()
172-
const applyColor = colors[this.#color] ?? colors.cyan
173-
const frame = this.#frames[this.#currentFrame]
174-
let string = `${frame ? applyColor(frame) : ''}${this.#text ? ` ${this.#text}` : ''}`
175-
if (string) {
176-
if (this.#indention.length) {
177-
string = `${this.#indention}${string}`
178-
}
179-
if (!this.#isInteractive) {
180-
string += '\n'
181-
}
155+
stop(finalText) {
156+
if (!this.isSpinning) {
157+
return this
182158
}
183-
this.clear()
184-
this.#write(string)
185-
if (this.#isInteractive) {
186-
this.#lines = this.#lineCount(string)
159+
160+
this.#isSpinning = false
161+
if (this.#timer) {
162+
clearInterval(this.#timer)
163+
this.#timer = undefined
187164
}
188-
}
189165

190-
#setTimer() {
191-
const timeout = setInterval(() => {
192-
this.#render()
193-
}, this.#interval)
194-
// Guard unref usage in case yocto-spinner is somehow built to run in a browser.
195-
// https://nodejs.org/api/timers.html#timeoutunref
196-
timeout?.unref?.()
197-
this.#timer = timeout
198-
}
166+
this.#showCursor()
167+
this.clear()
168+
this.#unsubscribeFromProcessEvents()
199169

200-
#showCursor() {
201-
if (this.#isInteractive) {
202-
this.#write('\u001B[?25h')
170+
if (finalText) {
171+
this.#stream.write(`${finalText}\n`)
203172
}
204-
}
205173

206-
#subscribeToExitEvents() {
207-
this.#signal?.addEventListener('abort', this.#exitHandlerBound)
208-
process.once('SIGINT', this.#exitHandlerBound)
209-
process.once('SIGTERM', this.#exitHandlerBound)
174+
return this
210175
}
211176

212177
#symbolStop(symbolType, text) {
213178
const symbols = getLogSymbols()
214179
return this.stop(`${symbols[symbolType]} ${text ?? this.#text}`)
215180
}
216181

217-
#unsubscribeFromExitEvents() {
218-
this.#signal?.removeEventListener('abort', this.#exitHandlerBound)
219-
process.off('SIGINT', this.#exitHandlerBound)
220-
process.off('SIGTERM', this.#exitHandlerBound)
182+
success(text) {
183+
return this.#symbolStop('success', text)
221184
}
222185

223-
#write(text) {
224-
this.#stream.write(text)
186+
error(text) {
187+
return this.#symbolStop('error', text)
225188
}
226189

227-
get color() {
228-
return this.#color
190+
warning(text) {
191+
return this.#symbolStop('warning', text)
229192
}
230193

231-
set color(value) {
232-
this.#color = value
233-
this.#render()
194+
info(text) {
195+
return this.#symbolStop('info', text)
234196
}
235197

236198
get isSpinning() {
237-
return this.#timer !== undefined
199+
return this.#isSpinning
238200
}
239201

240202
get text() {
241203
return this.#text
242204
}
243205

244206
set text(value) {
245-
const text = value ?? ''
246-
this.#text = typeof text === 'string' ? text : String(text)
207+
this.#text = value ?? ''
208+
this.#render()
209+
}
210+
211+
get color() {
212+
return this.#color
213+
}
214+
215+
set color(value) {
216+
this.#color = value
247217
this.#render()
248218
}
249219

250220
clear() {
251221
if (!this.#isInteractive) {
252222
return this
253223
}
224+
254225
this.#stream.cursorTo(0)
255-
for (let index = 0; index < this.#lines; index += 1) {
226+
227+
for (let index = 0; index < this.#lines; index++) {
256228
if (index > 0) {
257229
this.#stream.moveCursor(0, -1)
258230
}
231+
259232
this.#stream.clearLine(1)
260233
}
234+
261235
this.#lines = 0
262-
return this
263-
}
264236

265-
dedent(spaces = 2) {
266-
this.#indention = this.#indention.slice(0, -spaces)
267237
return this
268238
}
269239

270-
error(text) {
271-
return this.#symbolStop('error', text)
272-
}
240+
#render() {
241+
// Ensure we only update the spinner frame at the wanted interval,
242+
// even if the frame method is called more often.
243+
const now = Date.now()
244+
if (
245+
this.#currentFrame === -1 ||
246+
now - this.#lastSpinnerFrameTime >= this.#interval
247+
) {
248+
this.#currentFrame = ++this.#currentFrame % this.#frames.length
249+
this.#lastSpinnerFrameTime = now
250+
}
273251

274-
indent(spaces = 2) {
275-
this.#indention += ' '.repeat(spaces)
276-
return this
277-
}
252+
const colors = getYoctocolors()
253+
const applyColor = colors[this.#color] ?? colors.cyan
254+
const frame = this.#frames[this.#currentFrame]
255+
let string = `${applyColor(frame)} ${this.#text}`
278256

279-
info(text) {
280-
return this.#symbolStop('info', text)
257+
if (!this.#isInteractive) {
258+
string += '\n'
259+
}
260+
261+
this.clear()
262+
this.#write(string)
263+
264+
if (this.#isInteractive) {
265+
this.#lines = this.#lineCount(string)
266+
}
281267
}
282268

283-
resetIndent() {
284-
this.#indention = ''
285-
return this
269+
#write(text) {
270+
this.#stream.write(text)
286271
}
287272

288-
start(text) {
289-
if (text) {
290-
this.#text = text
291-
}
292-
if (this.isSpinning) {
293-
return this
273+
#lineCount(text) {
274+
const width = this.#stream.columns ?? defaultTtyColumns
275+
const lines = stripVTControlCharacters(text).split('\n')
276+
277+
let lineCount = 0
278+
for (const line of lines) {
279+
lineCount += Math.max(1, Math.ceil(line.length / width))
294280
}
295-
this.#hideCursor()
296-
this.#render()
297-
this.#setTimer()
298-
this.#subscribeToExitEvents()
299-
return this
281+
282+
return lineCount
300283
}
301284

302-
stop(finalText) {
303-
if (!this.isSpinning) {
304-
return this
285+
#hideCursor() {
286+
if (this.#isInteractive) {
287+
this.#write('\u001B[?25l')
305288
}
306-
this.#showCursor()
307-
this.clear()
308-
this.#clearTimer()
309-
this.#unsubscribeFromExitEvents()
310-
if (finalText) {
311-
this.#write(`${this.#indention}${finalText}\n`)
289+
}
290+
291+
#showCursor() {
292+
if (this.#isInteractive) {
293+
this.#write('\u001B[?25h')
312294
}
313-
return this
314295
}
315296

316-
success(text) {
317-
return this.#symbolStop('success', text)
297+
#subscribeToProcessEvents() {
298+
process.once('SIGINT', this.#exitHandlerBound)
299+
process.once('SIGTERM', this.#exitHandlerBound)
318300
}
319301

320-
warning(text) {
321-
return this.#symbolStop('warning', text)
302+
#unsubscribeFromProcessEvents() {
303+
process.off('SIGINT', this.#exitHandlerBound)
304+
process.off('SIGTERM', this.#exitHandlerBound)
305+
}
306+
307+
#exitHandler(signal) {
308+
if (this.isSpinning) {
309+
this.stop()
310+
}
311+
312+
// SIGINT: 128 + 2
313+
// SIGTERM: 128 + 15
314+
const exitCode = signal === 'SIGINT' ? 130 : signal === 'SIGTERM' ? 143 : 1
315+
// eslint-disable-next-line n/no-process-exit
316+
process.exit(exitCode)
322317
}
323318
}
324319

packages/npm/yocto-spinner/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@socketregistry/yocto-spinner",
3-
"version": "1.0.17",
3+
"version": "1.0.18",
44
"license": "MIT",
55
"description": "Socket.dev optimized package override for yocto-spinner",
66
"keywords": [

0 commit comments

Comments
 (0)