@synapsync/synk 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/README.md +480 -0
- package/ThirdPartyNoticeText.txt +125 -0
- package/bin/cli.mjs +14 -0
- package/dist/_chunks/libs/@clack/core.mjs +767 -0
- package/dist/_chunks/libs/@clack/prompts.mjs +196 -0
- package/dist/_chunks/libs/@kwsites/file-exists.mjs +562 -0
- package/dist/_chunks/libs/@kwsites/promise-deferred.mjs +37 -0
- package/dist/_chunks/libs/ansi-regex.mjs +4 -0
- package/dist/_chunks/libs/chalk.mjs +399 -0
- package/dist/_chunks/libs/cli-cursor.mjs +257 -0
- package/dist/_chunks/libs/cli-spinners.mjs +1656 -0
- package/dist/_chunks/libs/esprima.mjs +5338 -0
- package/dist/_chunks/libs/extend-shallow.mjs +31 -0
- package/dist/_chunks/libs/get-east-asian-width.mjs +18 -0
- package/dist/_chunks/libs/gray-matter.mjs +2596 -0
- package/dist/_chunks/libs/is-interactive.mjs +4 -0
- package/dist/_chunks/libs/is-unicode-supported.mjs +8 -0
- package/dist/_chunks/libs/log-symbols.mjs +70 -0
- package/dist/_chunks/libs/ora.mjs +460 -0
- package/dist/_chunks/libs/simple-git.mjs +3584 -0
- package/dist/_chunks/libs/xdg-basedir.mjs +14 -0
- package/dist/_chunks/rolldown-runtime.mjs +24 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +4066 -0
- package/package.json +116 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import y from "node:process";
|
|
2
|
+
function isUnicodeSupported() {
|
|
3
|
+
const { env } = y;
|
|
4
|
+
const { TERM, TERM_PROGRAM } = env;
|
|
5
|
+
if (y.platform !== "win32") return TERM !== "linux";
|
|
6
|
+
return Boolean(env.WT_SESSION) || Boolean(env.TERMINUS_SUBLIME) || env.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
7
|
+
}
|
|
8
|
+
export { isUnicodeSupported as t };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { t as isUnicodeSupported } from "./is-unicode-supported.mjs";
|
|
2
|
+
import tty from "node:tty";
|
|
3
|
+
const hasColors = tty?.WriteStream?.prototype?.hasColors?.() ?? false;
|
|
4
|
+
const format = (open, close) => {
|
|
5
|
+
if (!hasColors) return (input) => input;
|
|
6
|
+
const openCode = `\u001B[${open}m`;
|
|
7
|
+
const closeCode = `\u001B[${close}m`;
|
|
8
|
+
return (input) => {
|
|
9
|
+
const string = input + "";
|
|
10
|
+
let index = string.indexOf(closeCode);
|
|
11
|
+
if (index === -1) return openCode + string + closeCode;
|
|
12
|
+
let result = openCode;
|
|
13
|
+
let lastIndex = 0;
|
|
14
|
+
const replaceCode = (close === 22 ? closeCode : "") + openCode;
|
|
15
|
+
while (index !== -1) {
|
|
16
|
+
result += string.slice(lastIndex, index) + replaceCode;
|
|
17
|
+
lastIndex = index + closeCode.length;
|
|
18
|
+
index = string.indexOf(closeCode, lastIndex);
|
|
19
|
+
}
|
|
20
|
+
result += string.slice(lastIndex) + closeCode;
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
format(0, 0);
|
|
25
|
+
format(1, 22);
|
|
26
|
+
format(2, 22);
|
|
27
|
+
format(3, 23);
|
|
28
|
+
format(4, 24);
|
|
29
|
+
format(53, 55);
|
|
30
|
+
format(7, 27);
|
|
31
|
+
format(8, 28);
|
|
32
|
+
format(9, 29);
|
|
33
|
+
format(30, 39);
|
|
34
|
+
const red = format(31, 39);
|
|
35
|
+
const green = format(32, 39);
|
|
36
|
+
const yellow = format(33, 39);
|
|
37
|
+
const blue = format(34, 39);
|
|
38
|
+
format(35, 39);
|
|
39
|
+
format(36, 39);
|
|
40
|
+
format(37, 39);
|
|
41
|
+
format(90, 39);
|
|
42
|
+
format(40, 49);
|
|
43
|
+
format(41, 49);
|
|
44
|
+
format(42, 49);
|
|
45
|
+
format(43, 49);
|
|
46
|
+
format(44, 49);
|
|
47
|
+
format(45, 49);
|
|
48
|
+
format(46, 49);
|
|
49
|
+
format(47, 49);
|
|
50
|
+
format(100, 49);
|
|
51
|
+
format(91, 39);
|
|
52
|
+
format(92, 39);
|
|
53
|
+
format(93, 39);
|
|
54
|
+
format(94, 39);
|
|
55
|
+
format(95, 39);
|
|
56
|
+
format(96, 39);
|
|
57
|
+
format(97, 39);
|
|
58
|
+
format(101, 49);
|
|
59
|
+
format(102, 49);
|
|
60
|
+
format(103, 49);
|
|
61
|
+
format(104, 49);
|
|
62
|
+
format(105, 49);
|
|
63
|
+
format(106, 49);
|
|
64
|
+
format(107, 49);
|
|
65
|
+
const _isUnicodeSupported = isUnicodeSupported();
|
|
66
|
+
const info = blue(_isUnicodeSupported ? "ℹ" : "i");
|
|
67
|
+
const success = green(_isUnicodeSupported ? "✔" : "√");
|
|
68
|
+
const warning = yellow(_isUnicodeSupported ? "⚠" : "‼");
|
|
69
|
+
const error = red(_isUnicodeSupported ? "✖" : "×");
|
|
70
|
+
export { warning as i, info as n, success as r, error as t };
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import { t as source_default } from "./chalk.mjs";
|
|
2
|
+
import { t as cli_cursor_default } from "./cli-cursor.mjs";
|
|
3
|
+
import { t as cli_spinners_default } from "./cli-spinners.mjs";
|
|
4
|
+
import { i as warning, n as info, r as success, t as error } from "./log-symbols.mjs";
|
|
5
|
+
import { t as isUnicodeSupported } from "./is-unicode-supported.mjs";
|
|
6
|
+
import { t as ansiRegex } from "./ansi-regex.mjs";
|
|
7
|
+
import { t as eastAsianWidth } from "./get-east-asian-width.mjs";
|
|
8
|
+
import { t as isInteractive } from "./is-interactive.mjs";
|
|
9
|
+
import y from "node:process";
|
|
10
|
+
import { stripVTControlCharacters } from "node:util";
|
|
11
|
+
const regex = ansiRegex();
|
|
12
|
+
function stripAnsi(string) {
|
|
13
|
+
if (typeof string !== "string") throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
|
|
14
|
+
return string.replace(regex, "");
|
|
15
|
+
}
|
|
16
|
+
const segmenter = new Intl.Segmenter();
|
|
17
|
+
const zeroWidthClusterRegex = /^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Mark}|\p{Surrogate})+$/v;
|
|
18
|
+
const leadingNonPrintingRegex = /^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
|
|
19
|
+
const rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
|
|
20
|
+
function baseVisible(segment) {
|
|
21
|
+
return segment.replace(leadingNonPrintingRegex, "");
|
|
22
|
+
}
|
|
23
|
+
function isZeroWidthCluster(segment) {
|
|
24
|
+
return zeroWidthClusterRegex.test(segment);
|
|
25
|
+
}
|
|
26
|
+
function trailingHalfwidthWidth(segment, eastAsianWidthOptions) {
|
|
27
|
+
let extra = 0;
|
|
28
|
+
if (segment.length > 1) {
|
|
29
|
+
for (const char of segment.slice(1)) if (char >= "" && char <= "") extra += eastAsianWidth(char.codePointAt(0), eastAsianWidthOptions);
|
|
30
|
+
}
|
|
31
|
+
return extra;
|
|
32
|
+
}
|
|
33
|
+
function stringWidth(input, options = {}) {
|
|
34
|
+
if (typeof input !== "string" || input.length === 0) return 0;
|
|
35
|
+
const { ambiguousIsNarrow = true, countAnsiEscapeCodes = false } = options;
|
|
36
|
+
let string = input;
|
|
37
|
+
if (!countAnsiEscapeCodes) string = stripAnsi(string);
|
|
38
|
+
if (string.length === 0) return 0;
|
|
39
|
+
let width = 0;
|
|
40
|
+
const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
|
|
41
|
+
for (const { segment } of segmenter.segment(string)) {
|
|
42
|
+
if (isZeroWidthCluster(segment)) continue;
|
|
43
|
+
if (rgiEmojiRegex.test(segment)) {
|
|
44
|
+
width += 2;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const codePoint = baseVisible(segment).codePointAt(0);
|
|
48
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
49
|
+
width += trailingHalfwidthWidth(segment, eastAsianWidthOptions);
|
|
50
|
+
}
|
|
51
|
+
return width;
|
|
52
|
+
}
|
|
53
|
+
const ASCII_ETX_CODE = 3;
|
|
54
|
+
var StdinDiscarder = class {
|
|
55
|
+
#activeCount = 0;
|
|
56
|
+
#stdin;
|
|
57
|
+
#stdinWasPaused = false;
|
|
58
|
+
#stdinWasRaw = false;
|
|
59
|
+
#handleInputBound = (chunk) => {
|
|
60
|
+
if (!chunk?.length) return;
|
|
61
|
+
if ((typeof chunk === "string" ? chunk.codePointAt(0) : chunk[0]) === ASCII_ETX_CODE) if (y.listenerCount("SIGINT") > 0) y.emit("SIGINT");
|
|
62
|
+
else y.kill(y.pid, "SIGINT");
|
|
63
|
+
};
|
|
64
|
+
start() {
|
|
65
|
+
this.#activeCount++;
|
|
66
|
+
if (this.#activeCount === 1) this.#realStart();
|
|
67
|
+
}
|
|
68
|
+
stop() {
|
|
69
|
+
if (this.#activeCount === 0) return;
|
|
70
|
+
if (--this.#activeCount === 0) this.#realStop();
|
|
71
|
+
}
|
|
72
|
+
#realStart() {
|
|
73
|
+
const { stdin } = y;
|
|
74
|
+
if (y.platform === "win32" || !stdin?.isTTY || typeof stdin.setRawMode !== "function") {
|
|
75
|
+
this.#stdin = void 0;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.#stdin = stdin;
|
|
79
|
+
this.#stdinWasPaused = stdin.isPaused();
|
|
80
|
+
this.#stdinWasRaw = Boolean(stdin.isRaw);
|
|
81
|
+
stdin.setRawMode(true);
|
|
82
|
+
stdin.prependListener("data", this.#handleInputBound);
|
|
83
|
+
if (this.#stdinWasPaused) stdin.resume();
|
|
84
|
+
}
|
|
85
|
+
#realStop() {
|
|
86
|
+
if (!this.#stdin) return;
|
|
87
|
+
const stdin = this.#stdin;
|
|
88
|
+
stdin.off("data", this.#handleInputBound);
|
|
89
|
+
if (stdin.isTTY) stdin.setRawMode?.(this.#stdinWasRaw);
|
|
90
|
+
if (this.#stdinWasPaused) stdin.pause();
|
|
91
|
+
this.#stdin = void 0;
|
|
92
|
+
this.#stdinWasPaused = false;
|
|
93
|
+
this.#stdinWasRaw = false;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const stdinDiscarder = new StdinDiscarder();
|
|
97
|
+
var stdin_discarder_default = Object.freeze(stdinDiscarder);
|
|
98
|
+
const RENDER_DEFERRAL_TIMEOUT = 200;
|
|
99
|
+
const SYNCHRONIZED_OUTPUT_ENABLE = "\x1B[?2026h";
|
|
100
|
+
const SYNCHRONIZED_OUTPUT_DISABLE = "\x1B[?2026l";
|
|
101
|
+
const activeHooksPerStream = /* @__PURE__ */ new Map();
|
|
102
|
+
var Ora = class {
|
|
103
|
+
#linesToClear = 0;
|
|
104
|
+
#frameIndex = -1;
|
|
105
|
+
#lastFrameTime = 0;
|
|
106
|
+
#options;
|
|
107
|
+
#spinner;
|
|
108
|
+
#stream;
|
|
109
|
+
#id;
|
|
110
|
+
#hookedStreams = /* @__PURE__ */ new Map();
|
|
111
|
+
#isInternalWrite = false;
|
|
112
|
+
#drainHandler;
|
|
113
|
+
#deferRenderTimer;
|
|
114
|
+
#isDiscardingStdin = false;
|
|
115
|
+
color;
|
|
116
|
+
#internalWrite(fn) {
|
|
117
|
+
this.#isInternalWrite = true;
|
|
118
|
+
try {
|
|
119
|
+
return fn();
|
|
120
|
+
} finally {
|
|
121
|
+
this.#isInternalWrite = false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
#tryRender() {
|
|
125
|
+
if (this.isSpinning) this.render();
|
|
126
|
+
}
|
|
127
|
+
#stringifyChunk(chunk, encoding) {
|
|
128
|
+
if (chunk === void 0 || chunk === null) return "";
|
|
129
|
+
if (typeof chunk === "string") return chunk;
|
|
130
|
+
if (Buffer.isBuffer(chunk) || ArrayBuffer.isView(chunk)) {
|
|
131
|
+
const normalizedEncoding = typeof encoding === "string" && encoding && encoding !== "buffer" ? encoding : "utf8";
|
|
132
|
+
return Buffer.from(chunk).toString(normalizedEncoding);
|
|
133
|
+
}
|
|
134
|
+
return String(chunk);
|
|
135
|
+
}
|
|
136
|
+
#chunkTerminatesLine(chunkString) {
|
|
137
|
+
if (!chunkString) return false;
|
|
138
|
+
const lastCharacter = chunkString.at(-1);
|
|
139
|
+
return lastCharacter === "\n" || lastCharacter === "\r";
|
|
140
|
+
}
|
|
141
|
+
#scheduleRenderDeferral() {
|
|
142
|
+
if (this.#deferRenderTimer) return;
|
|
143
|
+
this.#deferRenderTimer = setTimeout(() => {
|
|
144
|
+
this.#deferRenderTimer = void 0;
|
|
145
|
+
if (this.isSpinning) this.#tryRender();
|
|
146
|
+
}, RENDER_DEFERRAL_TIMEOUT);
|
|
147
|
+
if (typeof this.#deferRenderTimer?.unref === "function") this.#deferRenderTimer.unref();
|
|
148
|
+
}
|
|
149
|
+
#clearRenderDeferral() {
|
|
150
|
+
if (this.#deferRenderTimer) {
|
|
151
|
+
clearTimeout(this.#deferRenderTimer);
|
|
152
|
+
this.#deferRenderTimer = void 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
#buildOutputLine(symbol, text, prefixText, suffixText) {
|
|
156
|
+
const fullPrefixText = this.#getFullPrefixText(prefixText, " ");
|
|
157
|
+
const fullText = typeof text === "string" ? (symbol ? " " : "") + text : "";
|
|
158
|
+
const fullSuffixText = this.#getFullSuffixText(suffixText, " ");
|
|
159
|
+
return fullPrefixText + symbol + fullText + fullSuffixText;
|
|
160
|
+
}
|
|
161
|
+
constructor(options) {
|
|
162
|
+
if (typeof options === "string") options = { text: options };
|
|
163
|
+
this.#options = {
|
|
164
|
+
color: "cyan",
|
|
165
|
+
stream: y.stderr,
|
|
166
|
+
discardStdin: true,
|
|
167
|
+
hideCursor: true,
|
|
168
|
+
...options
|
|
169
|
+
};
|
|
170
|
+
this.color = this.#options.color;
|
|
171
|
+
this.#stream = this.#options.stream;
|
|
172
|
+
if (typeof this.#options.isEnabled !== "boolean") this.#options.isEnabled = isInteractive({ stream: this.#stream });
|
|
173
|
+
if (typeof this.#options.isSilent !== "boolean") this.#options.isSilent = false;
|
|
174
|
+
const userInterval = this.#options.interval;
|
|
175
|
+
this.spinner = this.#options.spinner;
|
|
176
|
+
this.#options.interval = userInterval;
|
|
177
|
+
this.text = this.#options.text;
|
|
178
|
+
this.prefixText = this.#options.prefixText;
|
|
179
|
+
this.suffixText = this.#options.suffixText;
|
|
180
|
+
this.indent = this.#options.indent;
|
|
181
|
+
if (y.env.NODE_ENV === "test") {
|
|
182
|
+
this._stream = this.#stream;
|
|
183
|
+
this._isEnabled = this.#options.isEnabled;
|
|
184
|
+
Object.defineProperty(this, "_linesToClear", {
|
|
185
|
+
get() {
|
|
186
|
+
return this.#linesToClear;
|
|
187
|
+
},
|
|
188
|
+
set(newValue) {
|
|
189
|
+
this.#linesToClear = newValue;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
Object.defineProperty(this, "_frameIndex", { get() {
|
|
193
|
+
return this.#frameIndex;
|
|
194
|
+
} });
|
|
195
|
+
Object.defineProperty(this, "_lineCount", { get() {
|
|
196
|
+
const columns = this.#stream.columns ?? 80;
|
|
197
|
+
const prefixText = typeof this.#options.prefixText === "function" ? "" : this.#options.prefixText;
|
|
198
|
+
const suffixText = typeof this.#options.suffixText === "function" ? "" : this.#options.suffixText;
|
|
199
|
+
const fullPrefixText = typeof prefixText === "string" && prefixText !== "" ? prefixText + " " : "";
|
|
200
|
+
const fullSuffixText = typeof suffixText === "string" && suffixText !== "" ? " " + suffixText : "";
|
|
201
|
+
const fullText = " ".repeat(this.#options.indent) + fullPrefixText + "-" + (typeof this.#options.text === "string" ? " " + this.#options.text : "") + fullSuffixText;
|
|
202
|
+
return this.#computeLineCountFrom(fullText, columns);
|
|
203
|
+
} });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
get indent() {
|
|
207
|
+
return this.#options.indent;
|
|
208
|
+
}
|
|
209
|
+
set indent(indent = 0) {
|
|
210
|
+
if (!(indent >= 0 && Number.isInteger(indent))) throw new Error("The `indent` option must be an integer from 0 and up");
|
|
211
|
+
this.#options.indent = indent;
|
|
212
|
+
}
|
|
213
|
+
get interval() {
|
|
214
|
+
return this.#options.interval ?? this.#spinner.interval ?? 100;
|
|
215
|
+
}
|
|
216
|
+
get spinner() {
|
|
217
|
+
return this.#spinner;
|
|
218
|
+
}
|
|
219
|
+
set spinner(spinner) {
|
|
220
|
+
this.#frameIndex = -1;
|
|
221
|
+
this.#options.interval = void 0;
|
|
222
|
+
if (typeof spinner === "object") {
|
|
223
|
+
if (!Array.isArray(spinner.frames) || spinner.frames.length === 0 || spinner.frames.some((frame) => typeof frame !== "string")) throw new Error("The given spinner must have a non-empty `frames` array of strings");
|
|
224
|
+
if (spinner.interval !== void 0 && !(Number.isInteger(spinner.interval) && spinner.interval > 0)) throw new Error("`spinner.interval` must be a positive integer if provided");
|
|
225
|
+
this.#spinner = spinner;
|
|
226
|
+
} else if (!isUnicodeSupported()) this.#spinner = cli_spinners_default.line;
|
|
227
|
+
else if (spinner === void 0) this.#spinner = cli_spinners_default.dots;
|
|
228
|
+
else if (spinner !== "default" && cli_spinners_default[spinner]) this.#spinner = cli_spinners_default[spinner];
|
|
229
|
+
else throw new Error(`There is no built-in spinner named '${spinner}'. See https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json for a full list.`);
|
|
230
|
+
}
|
|
231
|
+
get text() {
|
|
232
|
+
return this.#options.text;
|
|
233
|
+
}
|
|
234
|
+
set text(value = "") {
|
|
235
|
+
this.#options.text = value;
|
|
236
|
+
}
|
|
237
|
+
get prefixText() {
|
|
238
|
+
return this.#options.prefixText;
|
|
239
|
+
}
|
|
240
|
+
set prefixText(value = "") {
|
|
241
|
+
this.#options.prefixText = value;
|
|
242
|
+
}
|
|
243
|
+
get suffixText() {
|
|
244
|
+
return this.#options.suffixText;
|
|
245
|
+
}
|
|
246
|
+
set suffixText(value = "") {
|
|
247
|
+
this.#options.suffixText = value;
|
|
248
|
+
}
|
|
249
|
+
get isSpinning() {
|
|
250
|
+
return this.#id !== void 0;
|
|
251
|
+
}
|
|
252
|
+
#formatAffix(value, separator, placeBefore = false) {
|
|
253
|
+
const resolved = typeof value === "function" ? value() : value;
|
|
254
|
+
if (typeof resolved === "string" && resolved !== "") return placeBefore ? separator + resolved : resolved + separator;
|
|
255
|
+
return "";
|
|
256
|
+
}
|
|
257
|
+
#getFullPrefixText(prefixText = this.#options.prefixText, postfix = " ") {
|
|
258
|
+
return this.#formatAffix(prefixText, postfix, false);
|
|
259
|
+
}
|
|
260
|
+
#getFullSuffixText(suffixText = this.#options.suffixText, prefix = " ") {
|
|
261
|
+
return this.#formatAffix(suffixText, prefix, true);
|
|
262
|
+
}
|
|
263
|
+
#computeLineCountFrom(text, columns) {
|
|
264
|
+
let count = 0;
|
|
265
|
+
for (const line of stripVTControlCharacters(text).split("\n")) count += Math.max(1, Math.ceil(stringWidth(line) / columns));
|
|
266
|
+
return count;
|
|
267
|
+
}
|
|
268
|
+
get isEnabled() {
|
|
269
|
+
return this.#options.isEnabled && !this.#options.isSilent;
|
|
270
|
+
}
|
|
271
|
+
set isEnabled(value) {
|
|
272
|
+
if (typeof value !== "boolean") throw new TypeError("The `isEnabled` option must be a boolean");
|
|
273
|
+
this.#options.isEnabled = value;
|
|
274
|
+
}
|
|
275
|
+
get isSilent() {
|
|
276
|
+
return this.#options.isSilent;
|
|
277
|
+
}
|
|
278
|
+
set isSilent(value) {
|
|
279
|
+
if (typeof value !== "boolean") throw new TypeError("The `isSilent` option must be a boolean");
|
|
280
|
+
this.#options.isSilent = value;
|
|
281
|
+
}
|
|
282
|
+
frame() {
|
|
283
|
+
const now = Date.now();
|
|
284
|
+
if (this.#frameIndex === -1 || now - this.#lastFrameTime >= this.interval) {
|
|
285
|
+
this.#frameIndex = (this.#frameIndex + 1) % this.#spinner.frames.length;
|
|
286
|
+
this.#lastFrameTime = now;
|
|
287
|
+
}
|
|
288
|
+
const { frames } = this.#spinner;
|
|
289
|
+
let frame = frames[this.#frameIndex];
|
|
290
|
+
if (this.color) frame = source_default[this.color](frame);
|
|
291
|
+
const fullPrefixText = this.#getFullPrefixText(this.#options.prefixText, " ");
|
|
292
|
+
const fullText = typeof this.text === "string" ? " " + this.text : "";
|
|
293
|
+
const fullSuffixText = this.#getFullSuffixText(this.#options.suffixText, " ");
|
|
294
|
+
return fullPrefixText + frame + fullText + fullSuffixText;
|
|
295
|
+
}
|
|
296
|
+
clear() {
|
|
297
|
+
if (!this.isEnabled || !this.#stream.isTTY) return this;
|
|
298
|
+
this.#internalWrite(() => {
|
|
299
|
+
this.#stream.cursorTo(0);
|
|
300
|
+
for (let index = 0; index < this.#linesToClear; index++) {
|
|
301
|
+
if (index > 0) this.#stream.moveCursor(0, -1);
|
|
302
|
+
this.#stream.clearLine(1);
|
|
303
|
+
}
|
|
304
|
+
if (this.#options.indent) this.#stream.cursorTo(this.#options.indent);
|
|
305
|
+
});
|
|
306
|
+
this.#linesToClear = 0;
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
#hookStream(stream) {
|
|
310
|
+
if (!stream || this.#hookedStreams.has(stream) || !stream.isTTY || typeof stream.write !== "function") return;
|
|
311
|
+
if (activeHooksPerStream.has(stream)) console.warn("[ora] Multiple concurrent spinners detected. This may cause visual corruption. Use one spinner at a time.");
|
|
312
|
+
const originalWrite = stream.write;
|
|
313
|
+
this.#hookedStreams.set(stream, originalWrite);
|
|
314
|
+
activeHooksPerStream.set(stream, this);
|
|
315
|
+
stream.write = (chunk, encoding, callback) => this.#hookedWrite(stream, originalWrite, chunk, encoding, callback);
|
|
316
|
+
}
|
|
317
|
+
#installHook() {
|
|
318
|
+
if (!this.isEnabled || this.#hookedStreams.size > 0) return;
|
|
319
|
+
const streamsToHook = new Set([
|
|
320
|
+
this.#stream,
|
|
321
|
+
y.stdout,
|
|
322
|
+
y.stderr
|
|
323
|
+
]);
|
|
324
|
+
for (const stream of streamsToHook) this.#hookStream(stream);
|
|
325
|
+
}
|
|
326
|
+
#uninstallHook() {
|
|
327
|
+
for (const [stream, originalWrite] of this.#hookedStreams) {
|
|
328
|
+
stream.write = originalWrite;
|
|
329
|
+
if (activeHooksPerStream.get(stream) === this) activeHooksPerStream.delete(stream);
|
|
330
|
+
}
|
|
331
|
+
this.#hookedStreams.clear();
|
|
332
|
+
}
|
|
333
|
+
#hookedWrite(stream, originalWrite, chunk, encoding, callback) {
|
|
334
|
+
if (typeof encoding === "function") {
|
|
335
|
+
callback = encoding;
|
|
336
|
+
encoding = void 0;
|
|
337
|
+
}
|
|
338
|
+
if (this.#isInternalWrite) return originalWrite.call(stream, chunk, encoding, callback);
|
|
339
|
+
this.clear();
|
|
340
|
+
const chunkString = this.#stringifyChunk(chunk, encoding);
|
|
341
|
+
const chunkTerminatesLine = this.#chunkTerminatesLine(chunkString);
|
|
342
|
+
const writeResult = originalWrite.call(stream, chunk, encoding, callback);
|
|
343
|
+
if (chunkTerminatesLine) this.#clearRenderDeferral();
|
|
344
|
+
else if (chunkString.length > 0) this.#scheduleRenderDeferral();
|
|
345
|
+
if (this.isSpinning && !this.#deferRenderTimer) this.render();
|
|
346
|
+
return writeResult;
|
|
347
|
+
}
|
|
348
|
+
render() {
|
|
349
|
+
if (!this.isEnabled || this.#drainHandler || this.#deferRenderTimer) return this;
|
|
350
|
+
const useSynchronizedOutput = this.#stream.isTTY;
|
|
351
|
+
let shouldDisableSynchronizedOutput = false;
|
|
352
|
+
try {
|
|
353
|
+
if (useSynchronizedOutput) {
|
|
354
|
+
this.#internalWrite(() => this.#stream.write(SYNCHRONIZED_OUTPUT_ENABLE));
|
|
355
|
+
shouldDisableSynchronizedOutput = true;
|
|
356
|
+
}
|
|
357
|
+
this.clear();
|
|
358
|
+
let frameContent = this.frame();
|
|
359
|
+
const columns = this.#stream.columns ?? 80;
|
|
360
|
+
const actualLineCount = this.#computeLineCountFrom(frameContent, columns);
|
|
361
|
+
const consoleHeight = this.#stream.rows;
|
|
362
|
+
if (consoleHeight && consoleHeight > 1 && actualLineCount > consoleHeight) {
|
|
363
|
+
const lines = frameContent.split("\n");
|
|
364
|
+
const maxLines = consoleHeight - 1;
|
|
365
|
+
frameContent = [...lines.slice(0, maxLines), "... (content truncated to fit terminal)"].join("\n");
|
|
366
|
+
}
|
|
367
|
+
if (this.#internalWrite(() => this.#stream.write(frameContent)) === false && this.#stream.isTTY) {
|
|
368
|
+
this.#drainHandler = () => {
|
|
369
|
+
this.#drainHandler = void 0;
|
|
370
|
+
this.#tryRender();
|
|
371
|
+
};
|
|
372
|
+
this.#stream.once("drain", this.#drainHandler);
|
|
373
|
+
}
|
|
374
|
+
this.#linesToClear = this.#computeLineCountFrom(frameContent, columns);
|
|
375
|
+
} finally {
|
|
376
|
+
if (shouldDisableSynchronizedOutput) this.#internalWrite(() => this.#stream.write(SYNCHRONIZED_OUTPUT_DISABLE));
|
|
377
|
+
}
|
|
378
|
+
return this;
|
|
379
|
+
}
|
|
380
|
+
start(text) {
|
|
381
|
+
if (text) this.text = text;
|
|
382
|
+
if (this.isSilent) return this;
|
|
383
|
+
if (!this.isEnabled) {
|
|
384
|
+
const symbol = this.text ? "-" : "";
|
|
385
|
+
const line = " ".repeat(this.#options.indent) + this.#buildOutputLine(symbol, this.text, this.#options.prefixText, this.#options.suffixText);
|
|
386
|
+
if (line.trim() !== "") this.#internalWrite(() => this.#stream.write(line + "\n"));
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
if (this.isSpinning) return this;
|
|
390
|
+
if (this.#options.hideCursor) cli_cursor_default.hide(this.#stream);
|
|
391
|
+
if (this.#options.discardStdin && y.stdin.isTTY) {
|
|
392
|
+
stdin_discarder_default.start();
|
|
393
|
+
this.#isDiscardingStdin = true;
|
|
394
|
+
}
|
|
395
|
+
this.#installHook();
|
|
396
|
+
this.render();
|
|
397
|
+
this.#id = setInterval(this.render.bind(this), this.interval);
|
|
398
|
+
return this;
|
|
399
|
+
}
|
|
400
|
+
stop() {
|
|
401
|
+
clearInterval(this.#id);
|
|
402
|
+
this.#id = void 0;
|
|
403
|
+
this.#frameIndex = -1;
|
|
404
|
+
this.#lastFrameTime = 0;
|
|
405
|
+
this.#clearRenderDeferral();
|
|
406
|
+
this.#uninstallHook();
|
|
407
|
+
if (this.#drainHandler) {
|
|
408
|
+
this.#stream.removeListener("drain", this.#drainHandler);
|
|
409
|
+
this.#drainHandler = void 0;
|
|
410
|
+
}
|
|
411
|
+
if (this.isEnabled) {
|
|
412
|
+
this.clear();
|
|
413
|
+
if (this.#options.hideCursor) cli_cursor_default.show(this.#stream);
|
|
414
|
+
}
|
|
415
|
+
if (this.#isDiscardingStdin) {
|
|
416
|
+
this.#isDiscardingStdin = false;
|
|
417
|
+
stdin_discarder_default.stop();
|
|
418
|
+
}
|
|
419
|
+
return this;
|
|
420
|
+
}
|
|
421
|
+
succeed(text) {
|
|
422
|
+
return this.stopAndPersist({
|
|
423
|
+
symbol: success,
|
|
424
|
+
text
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
fail(text) {
|
|
428
|
+
return this.stopAndPersist({
|
|
429
|
+
symbol: error,
|
|
430
|
+
text
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
warn(text) {
|
|
434
|
+
return this.stopAndPersist({
|
|
435
|
+
symbol: warning,
|
|
436
|
+
text
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
info(text) {
|
|
440
|
+
return this.stopAndPersist({
|
|
441
|
+
symbol: info,
|
|
442
|
+
text
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
stopAndPersist(options = {}) {
|
|
446
|
+
if (this.isSilent) return this;
|
|
447
|
+
const symbol = options.symbol ?? " ";
|
|
448
|
+
const text = options.text ?? this.text;
|
|
449
|
+
const prefixText = options.prefixText ?? this.#options.prefixText;
|
|
450
|
+
const suffixText = options.suffixText ?? this.#options.suffixText;
|
|
451
|
+
const textToWrite = this.#buildOutputLine(symbol, text, prefixText, suffixText) + "\n";
|
|
452
|
+
this.stop();
|
|
453
|
+
this.#internalWrite(() => this.#stream.write(textToWrite));
|
|
454
|
+
return this;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
function ora(options) {
|
|
458
|
+
return new Ora(options);
|
|
459
|
+
}
|
|
460
|
+
export { ora as t };
|