termkit 2.0.1 → 2.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/README.md +473 -3
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/index.d.ts +47 -96
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2560 -140
- package/dist/index.mjs +2538 -138
- package/dist/models/Bar.d.ts +125 -0
- package/dist/models/Bar.d.ts.map +1 -0
- package/dist/models/Chart.d.ts +106 -0
- package/dist/models/Chart.d.ts.map +1 -0
- package/dist/models/Column.d.ts +20 -0
- package/dist/models/Column.d.ts.map +1 -0
- package/dist/models/Command.d.ts +38 -0
- package/dist/models/Command.d.ts.map +1 -0
- package/dist/models/Input.d.ts +58 -0
- package/dist/models/Input.d.ts.map +1 -0
- package/dist/models/Log.d.ts +24 -0
- package/dist/models/Log.d.ts.map +1 -0
- package/dist/models/Markup.d.ts +17 -0
- package/dist/models/Markup.d.ts.map +1 -0
- package/dist/models/MultiBar.d.ts +17 -0
- package/dist/models/MultiBar.d.ts.map +1 -0
- package/dist/models/MultiSelect.d.ts +45 -0
- package/dist/models/MultiSelect.d.ts.map +1 -0
- package/dist/models/Option.d.ts +17 -0
- package/dist/models/Option.d.ts.map +1 -0
- package/dist/models/Scrollbox.d.ts +20 -0
- package/dist/models/Scrollbox.d.ts.map +1 -0
- package/dist/models/Select.d.ts +39 -0
- package/dist/models/Select.d.ts.map +1 -0
- package/dist/models/Spinner.d.ts +67 -0
- package/dist/models/Spinner.d.ts.map +1 -0
- package/dist/models/Table.d.ts +26 -0
- package/dist/models/Table.d.ts.map +1 -0
- package/dist/models/TermKit.d.ts +19 -0
- package/dist/models/TermKit.d.ts.map +1 -0
- package/dist/models/Variable.d.ts +28 -0
- package/dist/models/Variable.d.ts.map +1 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/cleanup.d.ts +2 -0
- package/dist/utils/cleanup.d.ts.map +1 -0
- package/dist/utils/color.d.ts +29 -0
- package/dist/utils/color.d.ts.map +1 -0
- package/dist/utils/findCommand.d.ts +3 -0
- package/dist/utils/findCommand.d.ts.map +1 -0
- package/dist/utils/findCommandVariables.d.ts +3 -0
- package/dist/utils/findCommandVariables.d.ts.map +1 -0
- package/dist/utils/findOption.d.ts +3 -0
- package/dist/utils/findOption.d.ts.map +1 -0
- package/dist/utils/findOptions.d.ts +3 -0
- package/dist/utils/findOptions.d.ts.map +1 -0
- package/dist/utils/findVariable.d.ts +5 -0
- package/dist/utils/findVariable.d.ts.map +1 -0
- package/dist/utils/findVariables.d.ts +3 -0
- package/dist/utils/findVariables.d.ts.map +1 -0
- package/dist/utils/getVariables.d.ts +3 -0
- package/dist/utils/getVariables.d.ts.map +1 -0
- package/dist/utils/padLeft.d.ts +2 -0
- package/dist/utils/padLeft.d.ts.map +1 -0
- package/dist/utils/padRight.d.ts +2 -0
- package/dist/utils/padRight.d.ts.map +1 -0
- package/dist/utils/padSides.d.ts +2 -0
- package/dist/utils/padSides.d.ts.map +1 -0
- package/dist/utils/stringLength.d.ts +2 -0
- package/dist/utils/stringLength.d.ts.map +1 -0
- package/dist/utils/truncate.d.ts +2 -0
- package/dist/utils/truncate.d.ts.map +1 -0
- package/dist/utils/wrap.d.ts +2 -0
- package/dist/utils/wrap.d.ts.map +1 -0
- package/package.json +35 -7
- package/dist/index.d.mts +0 -99
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,122 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
1
7
|
// src/models/Command.ts
|
|
2
8
|
import cosmetic from "cosmetic";
|
|
3
9
|
|
|
4
|
-
// src/
|
|
10
|
+
// src/config.ts
|
|
11
|
+
var isLegacyTerminal = process.env.TERM === "dumb" || process.platform === "win32" && !process.env.WT_SESSION && process.env.TERM_PROGRAM !== "vscode" && process.env.TERM_PROGRAM !== "Hyper";
|
|
12
|
+
var config = {
|
|
13
|
+
color: "cyan",
|
|
14
|
+
pulseColors: ["#06b6d4", "#67e8f9"],
|
|
15
|
+
glyphs: !isLegacyTerminal,
|
|
16
|
+
interactive: false
|
|
17
|
+
};
|
|
18
|
+
function configure(opts) {
|
|
19
|
+
if (opts.color) config.color = opts.color;
|
|
20
|
+
if (opts.pulseColors) config.pulseColors = opts.pulseColors;
|
|
21
|
+
if (opts.glyphs !== void 0) config.glyphs = opts.glyphs;
|
|
22
|
+
if (opts.interactive !== void 0) config.interactive = opts.interactive;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/models/Variable.ts
|
|
26
|
+
var Variable = class {
|
|
27
|
+
constructor(data) {
|
|
28
|
+
this.array = false;
|
|
29
|
+
this.default = null;
|
|
30
|
+
this.enum = null;
|
|
31
|
+
this.max = null;
|
|
32
|
+
this.min = null;
|
|
33
|
+
this.name = null;
|
|
34
|
+
this.raw = null;
|
|
35
|
+
this.required = false;
|
|
36
|
+
this.type = "string";
|
|
37
|
+
this.value = null;
|
|
38
|
+
if (!data) return;
|
|
39
|
+
if (data.array) this.array = data.array;
|
|
40
|
+
if (data.default !== void 0) this.default = data.default;
|
|
41
|
+
if (data.enum) this.enum = data.enum;
|
|
42
|
+
if (data.max !== void 0) this.max = data.max;
|
|
43
|
+
if (data.min !== void 0) this.min = data.min;
|
|
44
|
+
if (data.name) this.name = data.name;
|
|
45
|
+
if (data.raw) this.raw = data.raw;
|
|
46
|
+
if (data.required) this.required = data.required;
|
|
47
|
+
if (data.type) this.type = data.type;
|
|
48
|
+
if (this.array) this.value = [];
|
|
49
|
+
}
|
|
50
|
+
get hint() {
|
|
51
|
+
const parts = [];
|
|
52
|
+
if (this.type === "enum" && this.enum) parts.push(this.enum.join("|"));
|
|
53
|
+
if (this.min !== null && this.max !== null) parts.push(`${this.min}\u2013${this.max}`);
|
|
54
|
+
else if (this.min !== null) parts.push(`>= ${this.min}`);
|
|
55
|
+
else if (this.max !== null) parts.push(`<= ${this.max}`);
|
|
56
|
+
if (this.default !== null) parts.push(`default: ${this.default}`);
|
|
57
|
+
return parts.length > 0 ? `(${parts.join(", ")})` : null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/utils/getVariables.ts
|
|
62
|
+
function parseName(raw) {
|
|
63
|
+
const colon = raw.indexOf(":");
|
|
64
|
+
if (colon === -1) return { name: raw, type: "string" };
|
|
65
|
+
const name = raw.slice(0, colon);
|
|
66
|
+
const rest = raw.slice(colon + 1);
|
|
67
|
+
const eqIdx = rest.lastIndexOf("=");
|
|
68
|
+
const typeStr = eqIdx !== -1 ? rest.slice(0, eqIdx) : rest;
|
|
69
|
+
const defaultValue = eqIdx !== -1 ? rest.slice(eqIdx + 1) : void 0;
|
|
70
|
+
const rangeMatch = typeStr.match(/^([a-z]+)\((-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)\)$/);
|
|
71
|
+
if (rangeMatch) {
|
|
72
|
+
return { name, type: rangeMatch[1], min: Number(rangeMatch[2]), max: Number(rangeMatch[3]), default: defaultValue };
|
|
73
|
+
}
|
|
74
|
+
if (typeStr.includes("|")) {
|
|
75
|
+
return { name, type: "enum", enum: typeStr.split("|"), default: defaultValue };
|
|
76
|
+
}
|
|
77
|
+
return { name, type: typeStr, default: defaultValue };
|
|
78
|
+
}
|
|
79
|
+
function getVariables(string) {
|
|
80
|
+
const results = [];
|
|
81
|
+
for (const part of string.split(" ")) {
|
|
82
|
+
const trimmed = part.trim();
|
|
83
|
+
if (!trimmed) continue;
|
|
84
|
+
if (trimmed.startsWith("<") && trimmed.endsWith(">")) {
|
|
85
|
+
const { name, type, enum: enumValues, default: def, min, max } = parseName(trimmed.slice(1, -1));
|
|
86
|
+
results.push(new Variable({ default: def, enum: enumValues, max, min, name, raw: trimmed, required: true, type }));
|
|
87
|
+
} else if (trimmed.startsWith("[") && trimmed.endsWith("...]")) {
|
|
88
|
+
const { name, type, enum: enumValues, default: def, min, max } = parseName(trimmed.slice(1, -4));
|
|
89
|
+
results.push(new Variable({ array: true, default: def, enum: enumValues, max, min, name, raw: trimmed, type }));
|
|
90
|
+
} else if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
91
|
+
const { name, type, enum: enumValues, default: def, min, max } = parseName(trimmed.slice(1, -1));
|
|
92
|
+
results.push(new Variable({ default: def, enum: enumValues, max, min, name, raw: trimmed, type }));
|
|
93
|
+
} else {
|
|
94
|
+
throw new Error(`Unrecognized variable description: ${trimmed}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return results;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/models/Option.ts
|
|
101
|
+
var Option = class {
|
|
102
|
+
constructor(data) {
|
|
103
|
+
this.short = null;
|
|
104
|
+
this.long = null;
|
|
105
|
+
this.info = null;
|
|
106
|
+
this.variables = null;
|
|
107
|
+
if (!data) return;
|
|
108
|
+
if (data.short) this.short = data.short;
|
|
109
|
+
if (data.long) this.long = data.long;
|
|
110
|
+
if (data.info) this.info = data.info;
|
|
111
|
+
if (data.variables) this.variables = getVariables(data.variables);
|
|
112
|
+
}
|
|
113
|
+
description(info) {
|
|
114
|
+
this.info = info;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/utils/findCommand.ts
|
|
5
120
|
function findCommand(array, commands) {
|
|
6
121
|
for (const command2 of commands) {
|
|
7
122
|
if (array[0] === command2.name) {
|
|
@@ -12,49 +127,612 @@ function findCommand(array, commands) {
|
|
|
12
127
|
return null;
|
|
13
128
|
}
|
|
14
129
|
|
|
15
|
-
// src/
|
|
16
|
-
|
|
17
|
-
|
|
130
|
+
// src/utils/color.ts
|
|
131
|
+
var RESET = "\x1B[0m";
|
|
132
|
+
var SHOW_CURSOR = "\x1B[?25h";
|
|
133
|
+
var HIDE_CURSOR = "\x1B[?25l";
|
|
134
|
+
var BOLD = "\x1B[1m";
|
|
135
|
+
var FAINT = "\x1B[2m";
|
|
136
|
+
var GREEN = "\x1B[32m";
|
|
137
|
+
var RED = "\x1B[31m";
|
|
138
|
+
var YELLOW = "\x1B[33m";
|
|
139
|
+
var BLUE = "\x1B[34m";
|
|
140
|
+
var MAGENTA = "\x1B[35m";
|
|
141
|
+
var CYAN = "\x1B[36m";
|
|
142
|
+
var DIM = 0.35;
|
|
143
|
+
var SHIMMER_SPEED = 0.5;
|
|
144
|
+
process.on("exit", () => {
|
|
145
|
+
if (process.stdout.isTTY) process.stdout.write(SHOW_CURSOR);
|
|
146
|
+
});
|
|
147
|
+
process.on("SIGINT", () => process.exit());
|
|
148
|
+
function parseHex(hex) {
|
|
149
|
+
const n = parseInt(hex.replace("#", ""), 16);
|
|
150
|
+
return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
|
|
151
|
+
}
|
|
152
|
+
function lerpColor(a, b, t) {
|
|
153
|
+
return {
|
|
154
|
+
r: Math.round(a.r + (b.r - a.r) * t),
|
|
155
|
+
g: Math.round(a.g + (b.g - a.g) * t),
|
|
156
|
+
b: Math.round(a.b + (b.b - a.b) * t)
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function interpolateColor(colors, t) {
|
|
160
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
161
|
+
const segments = colors.length - 1;
|
|
162
|
+
const scaled = clamped * segments;
|
|
163
|
+
const i = Math.min(Math.floor(scaled), segments - 1);
|
|
164
|
+
return lerpColor(colors[i], colors[i + 1], scaled - i);
|
|
165
|
+
}
|
|
166
|
+
function formatColor(code, color) {
|
|
167
|
+
if (!process.stdout.isTTY) return "";
|
|
168
|
+
return `\x1B[${code};2;${color.r};${color.g};${color.b}m`;
|
|
169
|
+
}
|
|
170
|
+
function colorText(colorOrAnsi, text) {
|
|
171
|
+
if (!process.stdout.isTTY) return text;
|
|
172
|
+
if (colorOrAnsi.startsWith("#")) {
|
|
173
|
+
const c = parseHex(colorOrAnsi);
|
|
174
|
+
return `\x1B[38;2;${c.r};${c.g};${c.b}m${text}${RESET}`;
|
|
175
|
+
}
|
|
176
|
+
return `${colorOrAnsi}${text}${RESET}`;
|
|
177
|
+
}
|
|
178
|
+
function dimColor(c) {
|
|
179
|
+
return { r: Math.round(c.r * DIM), g: Math.round(c.g * DIM), b: Math.round(c.b * DIM) };
|
|
180
|
+
}
|
|
181
|
+
function shimmerFactor(t, phase, amplitude) {
|
|
182
|
+
const wave = 0.5 + 0.5 * Math.sin(2 * Math.PI * (t - phase));
|
|
183
|
+
return 1 - amplitude * (1 - wave);
|
|
184
|
+
}
|
|
185
|
+
function resolveColor(color) {
|
|
186
|
+
if (typeof color === "number") return `\x1B[38;5;${color}m`;
|
|
187
|
+
if (color.startsWith("#")) return color;
|
|
188
|
+
const map = {
|
|
189
|
+
black: "\x1B[30m",
|
|
190
|
+
red: "\x1B[31m",
|
|
191
|
+
green: "\x1B[32m",
|
|
192
|
+
yellow: "\x1B[33m",
|
|
193
|
+
blue: "\x1B[34m",
|
|
194
|
+
magenta: "\x1B[35m",
|
|
195
|
+
cyan: "\x1B[36m",
|
|
196
|
+
white: "\x1B[37m"
|
|
197
|
+
};
|
|
198
|
+
return map[color] ?? "\x1B[35m";
|
|
199
|
+
}
|
|
200
|
+
function applyShimmer(color, t, phase, amplitude) {
|
|
201
|
+
if (amplitude === 0) return color;
|
|
202
|
+
const factor = shimmerFactor(t, phase, amplitude);
|
|
203
|
+
return {
|
|
204
|
+
r: Math.round(color.r * factor),
|
|
205
|
+
g: Math.round(color.g * factor),
|
|
206
|
+
b: Math.round(color.b * factor)
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/utils/stringLength.ts
|
|
211
|
+
var ANSI_PATTERN = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
212
|
+
var stringLength = (string) => {
|
|
213
|
+
if (!string) return 0;
|
|
214
|
+
return string.replace(ANSI_PATTERN, "").length;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// src/models/Input.ts
|
|
218
|
+
var CLEAR_LINE = "\x1B[2K";
|
|
219
|
+
var Input = class {
|
|
220
|
+
constructor(options = {}) {
|
|
221
|
+
this.promptColor = options.promptColor ?? GREEN;
|
|
222
|
+
this.promptGlyph = options.promptGlyph ?? (config.glyphs ? "\u25C6" : ">");
|
|
223
|
+
this.inputColor = options.inputColor ?? "";
|
|
224
|
+
this.errorColor = options.errorColor ?? RED;
|
|
225
|
+
this.placeholder = options.placeholder ?? "";
|
|
226
|
+
this.mask = options.mask ?? false;
|
|
227
|
+
this.inline = options.inline ?? false;
|
|
228
|
+
this.required = options.required ?? true;
|
|
229
|
+
this.type = options.type ?? "string";
|
|
230
|
+
this.defaultValue = options.default ?? null;
|
|
231
|
+
this.enumValues = options.enum ?? null;
|
|
232
|
+
this.match = options.match ?? null;
|
|
233
|
+
this.errorMsg = options.errorMessage ?? null;
|
|
234
|
+
this.regex = options.regex ?? null;
|
|
235
|
+
this.min = options.min ?? null;
|
|
236
|
+
this.max = options.max ?? null;
|
|
237
|
+
this.minLength = options.minLength ?? null;
|
|
238
|
+
this.maxLength = options.maxLength ?? null;
|
|
239
|
+
}
|
|
240
|
+
validate(value) {
|
|
241
|
+
const fail = (msg) => this.errorMsg ?? msg;
|
|
242
|
+
if (this.type === "number") {
|
|
243
|
+
const n = Number(value);
|
|
244
|
+
if (isNaN(n)) return fail("Must be a valid number");
|
|
245
|
+
if (this.min !== null && n < this.min) return fail(`Must be at least ${this.min}`);
|
|
246
|
+
if (this.max !== null && n > this.max) return fail(`Must be at most ${this.max}`);
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
if (this.type === "integer") {
|
|
250
|
+
const n = Number(value);
|
|
251
|
+
if (!Number.isInteger(n)) return fail("Must be a whole number");
|
|
252
|
+
if (this.min !== null && n < this.min) return fail(`Must be at least ${this.min}`);
|
|
253
|
+
if (this.max !== null && n > this.max) return fail(`Must be at most ${this.max}`);
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
if (this.type === "enum" && this.enumValues) {
|
|
257
|
+
if (!this.enumValues.includes(value)) return fail(`Must be one of: ${this.enumValues.join(", ")}`);
|
|
258
|
+
}
|
|
259
|
+
if (this.match !== null && value !== this.match) return fail("Does not match");
|
|
260
|
+
if (this.regex && !this.regex.test(value)) return fail("Invalid format");
|
|
261
|
+
if (this.minLength !== null && value.length < this.minLength) return fail(`Must be at least ${this.minLength} characters`);
|
|
262
|
+
if (this.maxLength !== null && value.length > this.maxLength) return fail(`Must be at most ${this.maxLength} characters`);
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
coerce(value) {
|
|
266
|
+
if (this.type === "number") return Number(value);
|
|
267
|
+
if (this.type === "integer") return parseInt(value, 10);
|
|
268
|
+
return value;
|
|
269
|
+
}
|
|
270
|
+
async ask(prompt) {
|
|
271
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Input requires an interactive terminal");
|
|
272
|
+
if (this.type === "boolean") return this.askBoolean(prompt);
|
|
273
|
+
let inputStr = "";
|
|
274
|
+
let cursorPos = 0;
|
|
275
|
+
let error = null;
|
|
276
|
+
let hasErrorLine = false;
|
|
277
|
+
const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
|
|
278
|
+
const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
|
|
279
|
+
let promptLine = prompt;
|
|
280
|
+
if (this.type === "enum" && this.enumValues) {
|
|
281
|
+
promptLine += ` \x1B[2m(${this.enumValues.join("|")})\x1B[0m`;
|
|
282
|
+
}
|
|
283
|
+
if (!this.inline) process.stdout.write(`${glyph}${promptLine}
|
|
284
|
+
`);
|
|
285
|
+
const defaultStr = this.defaultValue !== null ? String(this.defaultValue) : "";
|
|
286
|
+
const getDisplayText = () => {
|
|
287
|
+
const raw = this.mask ? "\u2022".repeat(inputStr.length) : inputStr;
|
|
288
|
+
if (inputStr.length === 0 && defaultStr) return `\x1B[2m${this.placeholder || defaultStr}${RESET}`;
|
|
289
|
+
return this.inputColor ? colorText(this.inputColor, raw) : raw;
|
|
290
|
+
};
|
|
291
|
+
const renderInput = (redraw) => {
|
|
292
|
+
if (redraw && hasErrorLine) process.stdout.write("\x1B[1A");
|
|
293
|
+
const text = getDisplayText();
|
|
294
|
+
const line = this.inline ? `\r${CLEAR_LINE}${glyph}${promptLine} ${text}` : `\r${CLEAR_LINE}${indent}${text}`;
|
|
295
|
+
process.stdout.write(line);
|
|
296
|
+
if (error) {
|
|
297
|
+
process.stdout.write(`
|
|
298
|
+
\r${CLEAR_LINE}${indent}${colorText(this.errorColor, `\u2717 ${error}`)}`);
|
|
299
|
+
hasErrorLine = true;
|
|
300
|
+
} else {
|
|
301
|
+
if (hasErrorLine) {
|
|
302
|
+
process.stdout.write(`
|
|
303
|
+
\r${CLEAR_LINE}\x1B[1A${line}`);
|
|
304
|
+
}
|
|
305
|
+
hasErrorLine = false;
|
|
306
|
+
}
|
|
307
|
+
if (inputStr.length > 0 && cursorPos < inputStr.length && !error) {
|
|
308
|
+
process.stdout.write(`\x1B[${inputStr.length - cursorPos}D`);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
renderInput(false);
|
|
312
|
+
return new Promise((resolve) => {
|
|
313
|
+
const cleanup = () => {
|
|
314
|
+
if (hasErrorLine) process.stdout.write(`\r${CLEAR_LINE}\x1B[1A`);
|
|
315
|
+
const text = getDisplayText();
|
|
316
|
+
const line = this.inline ? `\r${CLEAR_LINE}${glyph}${promptLine} ${text}` : `\r${CLEAR_LINE}${indent}${text}`;
|
|
317
|
+
process.stdout.write(`${line}
|
|
318
|
+
`);
|
|
319
|
+
process.stdin.setRawMode(false);
|
|
320
|
+
process.stdin.pause();
|
|
321
|
+
process.stdin.removeListener("data", onKey);
|
|
322
|
+
};
|
|
323
|
+
const onKey = (key) => {
|
|
324
|
+
const str = key.toString();
|
|
325
|
+
if (str === "\r" || str === "\n") {
|
|
326
|
+
const value = inputStr.length === 0 && defaultStr ? defaultStr : inputStr;
|
|
327
|
+
const err = this.validate(value);
|
|
328
|
+
if (err) {
|
|
329
|
+
error = err;
|
|
330
|
+
renderInput(true);
|
|
331
|
+
} else {
|
|
332
|
+
const usingDefault = inputStr.length === 0 && this.defaultValue !== null;
|
|
333
|
+
if (usingDefault) inputStr = defaultStr;
|
|
334
|
+
cleanup();
|
|
335
|
+
resolve(usingDefault ? this.defaultValue : this.coerce(value));
|
|
336
|
+
}
|
|
337
|
+
} else if (str === "\x1B[D") {
|
|
338
|
+
cursorPos = Math.max(0, cursorPos - 1);
|
|
339
|
+
renderInput(true);
|
|
340
|
+
} else if (str === "\x1B[C") {
|
|
341
|
+
cursorPos = Math.min(inputStr.length, cursorPos + 1);
|
|
342
|
+
renderInput(true);
|
|
343
|
+
} else if (str === "\x1B[H" || str === "\x1B[1~" || str === "") {
|
|
344
|
+
cursorPos = 0;
|
|
345
|
+
renderInput(true);
|
|
346
|
+
} else if (str === "\x1B[F" || str === "\x1B[4~" || str === "") {
|
|
347
|
+
cursorPos = inputStr.length;
|
|
348
|
+
renderInput(true);
|
|
349
|
+
} else if (str === "\x1B[3~") {
|
|
350
|
+
if (cursorPos < inputStr.length) {
|
|
351
|
+
inputStr = inputStr.slice(0, cursorPos) + inputStr.slice(cursorPos + 1);
|
|
352
|
+
error = null;
|
|
353
|
+
renderInput(true);
|
|
354
|
+
}
|
|
355
|
+
} else if (str === "\x1B") {
|
|
356
|
+
if (!this.required) {
|
|
357
|
+
cleanup();
|
|
358
|
+
resolve(null);
|
|
359
|
+
}
|
|
360
|
+
} else if (str === "") {
|
|
361
|
+
cleanup();
|
|
362
|
+
process.exit();
|
|
363
|
+
} else if (str === "\x7F" || str === "\b") {
|
|
364
|
+
if (cursorPos > 0) {
|
|
365
|
+
inputStr = inputStr.slice(0, cursorPos - 1) + inputStr.slice(cursorPos);
|
|
366
|
+
cursorPos--;
|
|
367
|
+
error = null;
|
|
368
|
+
renderInput(true);
|
|
369
|
+
}
|
|
370
|
+
} else if (str.charCodeAt(0) >= 32) {
|
|
371
|
+
if (this.maxLength !== null && inputStr.length >= this.maxLength) return;
|
|
372
|
+
inputStr = inputStr.slice(0, cursorPos) + str + inputStr.slice(cursorPos);
|
|
373
|
+
cursorPos++;
|
|
374
|
+
error = null;
|
|
375
|
+
renderInput(true);
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
process.stdin.setRawMode(true);
|
|
379
|
+
process.stdin.resume();
|
|
380
|
+
process.stdin.on("data", onKey);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
async askBoolean(prompt) {
|
|
384
|
+
const hasDefault = this.defaultValue !== null;
|
|
385
|
+
const defaultBool = this.defaultValue === true || this.defaultValue === "y" || this.defaultValue === "Y" || this.defaultValue === 1;
|
|
386
|
+
const hint = hasDefault ? defaultBool ? "[Y/n]" : "[y/N]" : "[y/n]";
|
|
387
|
+
const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
|
|
388
|
+
const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
|
|
389
|
+
if (this.inline) {
|
|
390
|
+
process.stdout.write(`${glyph}${prompt} \x1B[2m${hint}${RESET} `);
|
|
391
|
+
} else {
|
|
392
|
+
process.stdout.write(`${glyph}${prompt} \x1B[2m${hint}${RESET}
|
|
393
|
+
`);
|
|
394
|
+
process.stdout.write(`${indent}`);
|
|
395
|
+
}
|
|
396
|
+
return new Promise((resolve) => {
|
|
397
|
+
const finish = (selection, value) => {
|
|
398
|
+
process.stdin.setRawMode(false);
|
|
399
|
+
process.stdin.pause();
|
|
400
|
+
process.stdin.removeListener("data", onKey);
|
|
401
|
+
if (this.inline) {
|
|
402
|
+
process.stdout.write(`\r${CLEAR_LINE}${glyph}${prompt} \x1B[2m${hint}${RESET} ${selection}
|
|
403
|
+
`);
|
|
404
|
+
} else {
|
|
405
|
+
process.stdout.write(`\r${CLEAR_LINE}${indent}${selection}
|
|
406
|
+
`);
|
|
407
|
+
}
|
|
408
|
+
resolve(value);
|
|
409
|
+
};
|
|
410
|
+
const onKey = (key) => {
|
|
411
|
+
const str = key.toString();
|
|
412
|
+
if (str === "\r" || str === "\n") {
|
|
413
|
+
if (hasDefault) finish(defaultBool ? "yes" : "no", defaultBool);
|
|
414
|
+
} else if (str === "y" || str === "Y") {
|
|
415
|
+
finish("yes", true);
|
|
416
|
+
} else if (str === "n" || str === "N") {
|
|
417
|
+
finish("no", false);
|
|
418
|
+
} else if (str === "\x1B") {
|
|
419
|
+
if (!this.required) finish("", null);
|
|
420
|
+
} else if (str === "") {
|
|
421
|
+
process.stdin.setRawMode(false);
|
|
422
|
+
process.stdin.pause();
|
|
423
|
+
process.stdin.removeListener("data", onKey);
|
|
424
|
+
process.exit();
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
process.stdin.setRawMode(true);
|
|
428
|
+
process.stdin.resume();
|
|
429
|
+
process.stdin.on("data", onKey);
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
async function input(prompt, options = {}) {
|
|
434
|
+
return new Input(options).ask(prompt);
|
|
435
|
+
}
|
|
436
|
+
async function confirm(prompt, options) {
|
|
437
|
+
return new Input({ ...options, type: "boolean" }).ask(prompt);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/utils/cleanup.ts
|
|
441
|
+
var fns = /* @__PURE__ */ new Set();
|
|
442
|
+
var installed = false;
|
|
443
|
+
function install() {
|
|
444
|
+
if (installed) return;
|
|
445
|
+
installed = true;
|
|
446
|
+
process.on("SIGINT", () => {
|
|
447
|
+
flush();
|
|
448
|
+
process.exit(130);
|
|
449
|
+
});
|
|
450
|
+
process.on("exit", flush);
|
|
451
|
+
}
|
|
452
|
+
function flush() {
|
|
453
|
+
for (const fn of fns) {
|
|
454
|
+
try {
|
|
455
|
+
fn();
|
|
456
|
+
} catch {
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
fns.clear();
|
|
460
|
+
}
|
|
461
|
+
function registerCleanup(fn) {
|
|
462
|
+
install();
|
|
463
|
+
fns.add(fn);
|
|
464
|
+
return () => {
|
|
465
|
+
fns.delete(fn);
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/models/Select.ts
|
|
470
|
+
var CURSOR_UP = (n) => `\x1B[${n}A`;
|
|
471
|
+
var Select = class {
|
|
472
|
+
constructor(options = {}) {
|
|
473
|
+
this._colorOffset = 0;
|
|
474
|
+
this._shimmerPhase = 0;
|
|
475
|
+
this.promptColor = options.promptColor ?? resolveColor(config.color);
|
|
476
|
+
this.promptGlyph = options.promptGlyph ?? (config.glyphs ? "\u25C6" : ">");
|
|
477
|
+
this.descriptionColor = options.descriptionColor ?? BLUE;
|
|
478
|
+
this.skipLabel = options.skipLabel ?? "Skip";
|
|
479
|
+
this.selectedPrefix = options.selectedPrefix ?? ">";
|
|
480
|
+
this.selectedSuffix = options.selectedSuffix ?? "<";
|
|
481
|
+
this.colorCycle = options.colorCycle ?? 1;
|
|
482
|
+
this.shimmer = options.shimmer ?? 0;
|
|
483
|
+
this.interval = options.interval ?? 80;
|
|
484
|
+
this.searchEnabled = options.search ?? false;
|
|
485
|
+
this.maxHeight = options.maxHeight;
|
|
486
|
+
const colors = options.colors ?? config.pulseColors;
|
|
487
|
+
this._parsedColors = colors.length >= 2 ? colors.map(parseHex) : [];
|
|
488
|
+
}
|
|
489
|
+
pulseColor() {
|
|
490
|
+
if (this._parsedColors.length < 2) return "";
|
|
491
|
+
const t = (this._colorOffset % 1 + 1) % 1;
|
|
492
|
+
const base2 = interpolateColor(this._parsedColors, t);
|
|
493
|
+
const color = applyShimmer(base2, 0.5, this._shimmerPhase, this.shimmer);
|
|
494
|
+
return formatColor(38, color);
|
|
495
|
+
}
|
|
496
|
+
async ask(prompt, items) {
|
|
497
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Select requires an interactive terminal");
|
|
498
|
+
let selectedIndex = 0;
|
|
499
|
+
let viewportOffset = 0;
|
|
500
|
+
let searchQuery = "";
|
|
501
|
+
let lastDrawnLines = 0;
|
|
502
|
+
const skipItem = { label: this.skipLabel };
|
|
503
|
+
const getFiltered = () => {
|
|
504
|
+
if (!this.searchEnabled || searchQuery === "") return items;
|
|
505
|
+
const q = searchQuery.toLowerCase();
|
|
506
|
+
return items.filter((item) => item.label.toLowerCase().includes(q) || (item.description?.toLowerCase().includes(q) ?? false));
|
|
507
|
+
};
|
|
508
|
+
process.stdout.write(HIDE_CURSOR);
|
|
509
|
+
const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
|
|
510
|
+
const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
|
|
511
|
+
process.stdout.write(`${glyph}${prompt}
|
|
512
|
+
`);
|
|
513
|
+
const renderList = (redraw) => {
|
|
514
|
+
const filtered = getFiltered();
|
|
515
|
+
const allItems = [...filtered, skipItem];
|
|
516
|
+
if (selectedIndex >= allItems.length) selectedIndex = allItems.length - 1;
|
|
517
|
+
if (this.maxHeight) {
|
|
518
|
+
if (selectedIndex < viewportOffset) viewportOffset = selectedIndex;
|
|
519
|
+
else if (selectedIndex >= viewportOffset + this.maxHeight) viewportOffset = selectedIndex - this.maxHeight + 1;
|
|
520
|
+
viewportOffset = Math.max(0, Math.min(viewportOffset, Math.max(0, allItems.length - this.maxHeight)));
|
|
521
|
+
}
|
|
522
|
+
const visibleStart = this.maxHeight ? viewportOffset : 0;
|
|
523
|
+
const visibleEnd = this.maxHeight ? Math.min(allItems.length, viewportOffset + this.maxHeight) : allItems.length;
|
|
524
|
+
if (redraw) {
|
|
525
|
+
if (lastDrawnLines > 0) process.stdout.write(CURSOR_UP(lastDrawnLines));
|
|
526
|
+
process.stdout.write("\r\x1B[0J");
|
|
527
|
+
}
|
|
528
|
+
lastDrawnLines = 0;
|
|
529
|
+
if (this.searchEnabled) {
|
|
530
|
+
process.stdout.write(`\r${indent}${colorText(this.promptColor, "/")} ${searchQuery}|
|
|
531
|
+
`);
|
|
532
|
+
lastDrawnLines++;
|
|
533
|
+
}
|
|
534
|
+
const pulse = this.pulseColor();
|
|
535
|
+
for (let i = visibleStart; i < visibleEnd; i++) {
|
|
536
|
+
const item = allItems[i];
|
|
537
|
+
const isSelected = i === selectedIndex;
|
|
538
|
+
const isSkip = i === filtered.length;
|
|
539
|
+
const relativeNum = i - visibleStart + 1;
|
|
540
|
+
const numStr = isSkip ? "0." : `${relativeNum}.`;
|
|
541
|
+
const desc = item.description ? ` ${colorText(this.descriptionColor, `\u2014 ${item.description}`)}` : "";
|
|
542
|
+
let marker, tail;
|
|
543
|
+
if (isSelected && pulse) {
|
|
544
|
+
marker = `${pulse}${this.selectedPrefix}${RESET}`;
|
|
545
|
+
tail = ` ${pulse}${this.selectedSuffix}${RESET}`;
|
|
546
|
+
} else {
|
|
547
|
+
const fallback = isSelected ? this.promptColor : "";
|
|
548
|
+
marker = fallback ? colorText(fallback, this.selectedPrefix) : " ".repeat(stringLength(this.selectedPrefix));
|
|
549
|
+
tail = isSelected ? ` ${colorText(this.promptColor, this.selectedSuffix)}` : "";
|
|
550
|
+
}
|
|
551
|
+
process.stdout.write(`\r${indent}${marker} ${numStr} ${item.label}${desc}${tail}
|
|
552
|
+
`);
|
|
553
|
+
lastDrawnLines++;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
renderList(false);
|
|
557
|
+
return new Promise((resolve) => {
|
|
558
|
+
let timer = null;
|
|
559
|
+
const deregisterCleanup = registerCleanup(() => {
|
|
560
|
+
if (timer) {
|
|
561
|
+
clearInterval(timer);
|
|
562
|
+
timer = null;
|
|
563
|
+
}
|
|
564
|
+
process.stdin.setRawMode(false);
|
|
565
|
+
process.stdin.pause();
|
|
566
|
+
process.stdin.removeListener("data", onKey);
|
|
567
|
+
process.stdout.write(SHOW_CURSOR);
|
|
568
|
+
});
|
|
569
|
+
const cleanup = () => {
|
|
570
|
+
deregisterCleanup();
|
|
571
|
+
if (timer) {
|
|
572
|
+
clearInterval(timer);
|
|
573
|
+
timer = null;
|
|
574
|
+
}
|
|
575
|
+
process.stdin.setRawMode(false);
|
|
576
|
+
process.stdin.pause();
|
|
577
|
+
process.stdin.removeListener("data", onKey);
|
|
578
|
+
process.stdout.write(SHOW_CURSOR);
|
|
579
|
+
};
|
|
580
|
+
if (this._parsedColors.length >= 2) {
|
|
581
|
+
timer = setInterval(() => {
|
|
582
|
+
this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
|
|
583
|
+
if (this.shimmer > 0) {
|
|
584
|
+
this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
|
|
585
|
+
}
|
|
586
|
+
renderList(true);
|
|
587
|
+
}, this.interval);
|
|
588
|
+
}
|
|
589
|
+
const onKey = (key) => {
|
|
590
|
+
const str = key.toString();
|
|
591
|
+
const filtered = getFiltered();
|
|
592
|
+
const allItems = [...filtered, skipItem];
|
|
593
|
+
if (str === "\x1B[A") {
|
|
594
|
+
selectedIndex = (selectedIndex - 1 + allItems.length) % allItems.length;
|
|
595
|
+
renderList(true);
|
|
596
|
+
} else if (str === "\x1B[B") {
|
|
597
|
+
selectedIndex = (selectedIndex + 1) % allItems.length;
|
|
598
|
+
renderList(true);
|
|
599
|
+
} else if (str === "\r" || str === "\n") {
|
|
600
|
+
cleanup();
|
|
601
|
+
resolve(selectedIndex === filtered.length ? null : filtered[selectedIndex] ?? null);
|
|
602
|
+
} else if (str === "") {
|
|
603
|
+
cleanup();
|
|
604
|
+
process.exit(130);
|
|
605
|
+
} else if (this.searchEnabled) {
|
|
606
|
+
if (str === "\x7F" || str === "\b") {
|
|
607
|
+
searchQuery = searchQuery.slice(0, -1);
|
|
608
|
+
const newFiltered = getFiltered();
|
|
609
|
+
if (selectedIndex >= newFiltered.length + 1) selectedIndex = Math.max(0, newFiltered.length);
|
|
610
|
+
viewportOffset = 0;
|
|
611
|
+
renderList(true);
|
|
612
|
+
} else if (str.length === 1 && str >= " ") {
|
|
613
|
+
searchQuery += str;
|
|
614
|
+
selectedIndex = 0;
|
|
615
|
+
viewportOffset = 0;
|
|
616
|
+
renderList(true);
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
const n = parseInt(str);
|
|
620
|
+
if (!isNaN(n) && n >= 0 && n <= Math.min(items.length, 9)) {
|
|
621
|
+
const visibleStart = this.maxHeight ? viewportOffset : 0;
|
|
622
|
+
selectedIndex = n === 0 ? allItems.length - 1 : visibleStart + n - 1;
|
|
623
|
+
selectedIndex = Math.max(0, Math.min(selectedIndex, allItems.length - 1));
|
|
624
|
+
renderList(true);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
process.stdin.setRawMode(true);
|
|
629
|
+
process.stdin.resume();
|
|
630
|
+
process.stdin.on("data", onKey);
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
async function select(prompt, items, options) {
|
|
635
|
+
return new Select(options).ask(prompt, items);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/utils/findVariable.ts
|
|
639
|
+
function coerce(value, type, enumValues, min = null, max = null) {
|
|
640
|
+
if (type === "number" || type === "integer") {
|
|
641
|
+
const n = Number(value);
|
|
642
|
+
if (type === "integer" && !Number.isInteger(n)) throw new Error(`Invalid value "${value}" \u2014 expected an integer`);
|
|
643
|
+
if (min !== null && n < min) throw new Error(`Invalid value "${value}" \u2014 must be >= ${min}`);
|
|
644
|
+
if (max !== null && n > max) throw new Error(`Invalid value "${value}" \u2014 must be <= ${max}`);
|
|
645
|
+
return n;
|
|
646
|
+
}
|
|
647
|
+
if (type === "string") {
|
|
648
|
+
if (min !== null && value.length < min) throw new Error(`Invalid value "${value}" \u2014 must be at least ${min} characters`);
|
|
649
|
+
if (max !== null && value.length > max) throw new Error(`Invalid value "${value}" \u2014 must be at most ${max} characters`);
|
|
650
|
+
return value;
|
|
651
|
+
}
|
|
18
652
|
if (type === "boolean") return value === "true";
|
|
653
|
+
if (type === "enum" && enumValues) {
|
|
654
|
+
if (!enumValues.includes(value)) {
|
|
655
|
+
throw new Error(`Invalid value "${value}" \u2014 expected one of: ${enumValues.join(", ")}`);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
19
658
|
return value;
|
|
20
659
|
}
|
|
21
|
-
function
|
|
660
|
+
async function promptForVariable(variable) {
|
|
661
|
+
const promptColor = resolveColor(config.color);
|
|
662
|
+
if (variable.type === "enum" && variable.enum) {
|
|
663
|
+
const items = variable.enum.map((label) => ({ label }));
|
|
664
|
+
const result = await new Select({ promptColor }).ask(`<${variable.name}>`, items);
|
|
665
|
+
return result !== null ? result.label : null;
|
|
666
|
+
}
|
|
667
|
+
const isNumeric = variable.type === "number" || variable.type === "integer";
|
|
668
|
+
return new Input({
|
|
669
|
+
type: variable.type,
|
|
670
|
+
promptColor,
|
|
671
|
+
min: isNumeric ? variable.min ?? void 0 : void 0,
|
|
672
|
+
max: isNumeric ? variable.max ?? void 0 : void 0,
|
|
673
|
+
minLength: !isNumeric ? variable.min ?? void 0 : void 0,
|
|
674
|
+
maxLength: !isNumeric ? variable.max ?? void 0 : void 0,
|
|
675
|
+
required: true
|
|
676
|
+
}).ask(`<${variable.name}>`);
|
|
677
|
+
}
|
|
678
|
+
async function findVariable(array, variable, commands) {
|
|
22
679
|
if (variable.array) {
|
|
23
680
|
const result = [];
|
|
24
681
|
while (array.length > 0 && !array[0].startsWith("-")) {
|
|
25
682
|
if (commands.includes(array[0])) break;
|
|
26
|
-
result.push(coerce(array.shift(), variable.type));
|
|
683
|
+
result.push(coerce(array.shift(), variable.type, variable.enum, variable.min, variable.max));
|
|
684
|
+
}
|
|
685
|
+
if (result.length === 0 && variable.required) {
|
|
686
|
+
if (config.interactive && process.stdout.isTTY) {
|
|
687
|
+
try {
|
|
688
|
+
const value = await promptForVariable(variable);
|
|
689
|
+
if (value !== null) return [value];
|
|
690
|
+
} catch {
|
|
691
|
+
throw new Error(`Missing required variable <${variable.name}> \u2014 stdin is not interactive`);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
throw new Error(`Missing required variable <${variable.name}>`);
|
|
27
695
|
}
|
|
28
|
-
if (result.length === 0 && variable.required) throw new Error(`Missing required variable <${variable.name}>`);
|
|
29
696
|
return result.length > 0 ? result : true;
|
|
30
697
|
}
|
|
31
698
|
if (array.length > 0 && !array[0].startsWith("-")) {
|
|
32
699
|
if ((!commands.includes(array[0]) || variable.required) && array[0] !== "help") {
|
|
33
|
-
return coerce(array.shift(), variable.type);
|
|
700
|
+
return coerce(array.shift(), variable.type, variable.enum, variable.min, variable.max);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (variable.required) {
|
|
704
|
+
if (config.interactive && process.stdout.isTTY) {
|
|
705
|
+
try {
|
|
706
|
+
const value = await promptForVariable(variable);
|
|
707
|
+
if (value !== null) return value;
|
|
708
|
+
} catch {
|
|
709
|
+
throw new Error(`Missing required variable <${variable.name}> \u2014 stdin is not interactive`);
|
|
710
|
+
}
|
|
34
711
|
}
|
|
712
|
+
throw new Error(`Missing required variable <${variable.name}>`);
|
|
35
713
|
}
|
|
36
|
-
if (variable.
|
|
714
|
+
if (variable.default !== null) return coerce(variable.default, variable.type, variable.enum);
|
|
37
715
|
return true;
|
|
38
716
|
}
|
|
39
717
|
|
|
40
|
-
// src/
|
|
41
|
-
function findCommandVariables(array, command2) {
|
|
718
|
+
// src/utils/findCommandVariables.ts
|
|
719
|
+
async function findCommandVariables(array, command2) {
|
|
42
720
|
if (!command2.variables) return null;
|
|
43
721
|
const result = {};
|
|
44
722
|
for (const variable of command2.variables) {
|
|
45
|
-
const value = findVariable(array, variable, command2.commandStrings);
|
|
723
|
+
const value = await findVariable(array, variable, command2.commandStrings);
|
|
46
724
|
if (value !== true) result[variable.name] = value;
|
|
47
725
|
}
|
|
48
726
|
return Object.keys(result).length > 0 ? result : null;
|
|
49
727
|
}
|
|
50
728
|
|
|
51
|
-
// src/
|
|
729
|
+
// src/utils/findOption.ts
|
|
52
730
|
function findOption(string, options) {
|
|
53
731
|
return options.find((o) => o.short === string || o.long === string);
|
|
54
732
|
}
|
|
55
733
|
|
|
56
|
-
// src/
|
|
57
|
-
function findVariables(base2, array, variables, commands) {
|
|
734
|
+
// src/utils/findVariables.ts
|
|
735
|
+
async function findVariables(base2, array, variables, commands) {
|
|
58
736
|
const result = {};
|
|
59
737
|
if (!variables) {
|
|
60
738
|
if (base2) result[base2] = true;
|
|
@@ -62,7 +740,7 @@ function findVariables(base2, array, variables, commands) {
|
|
|
62
740
|
}
|
|
63
741
|
if (variables.length > 1 && base2) result[base2] = {};
|
|
64
742
|
for (const variable of variables) {
|
|
65
|
-
const value = findVariable(array, variable, commands);
|
|
743
|
+
const value = await findVariable(array, variable, commands);
|
|
66
744
|
if (variables.length > 1 && base2) {
|
|
67
745
|
;
|
|
68
746
|
result[base2][variable.name] = value;
|
|
@@ -75,16 +753,24 @@ function findVariables(base2, array, variables, commands) {
|
|
|
75
753
|
return result;
|
|
76
754
|
}
|
|
77
755
|
|
|
78
|
-
// src/
|
|
79
|
-
function findOptions(array, command2) {
|
|
756
|
+
// src/utils/findOptions.ts
|
|
757
|
+
async function findOptions(array, command2) {
|
|
80
758
|
const result = {};
|
|
81
759
|
while (array.length > 0 && array[0].startsWith("-")) {
|
|
82
760
|
if (array[0].startsWith("--")) {
|
|
83
761
|
const raw = array.shift().slice(2);
|
|
762
|
+
if (raw.startsWith("no-")) {
|
|
763
|
+
const longName = raw.slice(3);
|
|
764
|
+
const negated = findOption(longName, command2.optionsArray);
|
|
765
|
+
if (negated?.long) {
|
|
766
|
+
result[negated.long] = false;
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
84
770
|
const option2 = findOption(raw, command2.optionsArray);
|
|
85
771
|
if (!option2) throw new Error(`Unknown Option: --${raw}`);
|
|
86
772
|
try {
|
|
87
|
-
Object.assign(result, findVariables(option2.long, array, option2.variables, command2.commandStrings));
|
|
773
|
+
Object.assign(result, await findVariables(option2.long, array, option2.variables, command2.commandStrings));
|
|
88
774
|
} catch (err) {
|
|
89
775
|
;
|
|
90
776
|
err.message += ` for --${option2.long}`;
|
|
@@ -95,10 +781,10 @@ function findOptions(array, command2) {
|
|
|
95
781
|
const short = string.slice(1, 2);
|
|
96
782
|
const option2 = findOption(short, command2.optionsArray);
|
|
97
783
|
if (!option2) throw new Error(`Unknown Option: -${short}`);
|
|
98
|
-
string = string.
|
|
784
|
+
string = "-" + string.slice(2);
|
|
99
785
|
if (string !== "-") array.unshift(string);
|
|
100
786
|
try {
|
|
101
|
-
Object.assign(result, findVariables(option2.long, array, option2.variables, command2.commandStrings));
|
|
787
|
+
Object.assign(result, await findVariables(option2.long, array, option2.variables, command2.commandStrings));
|
|
102
788
|
} catch (err) {
|
|
103
789
|
;
|
|
104
790
|
err.message += ` for --${option2.long}`;
|
|
@@ -109,74 +795,6 @@ function findOptions(array, command2) {
|
|
|
109
795
|
return result;
|
|
110
796
|
}
|
|
111
797
|
|
|
112
|
-
// src/models/Variable.ts
|
|
113
|
-
var Variable = class {
|
|
114
|
-
constructor(data) {
|
|
115
|
-
this.array = false;
|
|
116
|
-
this.name = null;
|
|
117
|
-
this.raw = null;
|
|
118
|
-
this.required = false;
|
|
119
|
-
this.type = "string";
|
|
120
|
-
this.value = null;
|
|
121
|
-
if (!data) return;
|
|
122
|
-
if (data.array) this.array = data.array;
|
|
123
|
-
if (data.name) this.name = data.name;
|
|
124
|
-
if (data.raw) this.raw = data.raw;
|
|
125
|
-
if (data.required) this.required = data.required;
|
|
126
|
-
if (data.type) this.type = data.type;
|
|
127
|
-
if (this.array) this.value = [];
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// src/helpers/getVariables.ts
|
|
132
|
-
function parseName(raw) {
|
|
133
|
-
const colon = raw.indexOf(":");
|
|
134
|
-
if (colon === -1) return { name: raw, type: "string" };
|
|
135
|
-
return {
|
|
136
|
-
name: raw.slice(0, colon),
|
|
137
|
-
type: raw.slice(colon + 1)
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
function getVariables(string) {
|
|
141
|
-
const results = [];
|
|
142
|
-
for (const part of string.split(" ")) {
|
|
143
|
-
const trimmed = part.trim();
|
|
144
|
-
if (!trimmed) continue;
|
|
145
|
-
if (trimmed.startsWith("<") && trimmed.endsWith(">")) {
|
|
146
|
-
const { name, type } = parseName(trimmed.slice(1, -1));
|
|
147
|
-
results.push(new Variable({ name, raw: trimmed, required: true, type }));
|
|
148
|
-
} else if (trimmed.startsWith("[") && trimmed.endsWith("...]")) {
|
|
149
|
-
const { name, type } = parseName(trimmed.slice(1, -4));
|
|
150
|
-
results.push(new Variable({ array: true, name, raw: trimmed, type }));
|
|
151
|
-
} else if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
152
|
-
const { name, type } = parseName(trimmed.slice(1, -1));
|
|
153
|
-
results.push(new Variable({ name, raw: trimmed, type }));
|
|
154
|
-
} else {
|
|
155
|
-
throw new Error(`Unrecognized variable description: ${trimmed}`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return results;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// src/models/Option.ts
|
|
162
|
-
var Option = class {
|
|
163
|
-
constructor(data) {
|
|
164
|
-
this.short = null;
|
|
165
|
-
this.long = null;
|
|
166
|
-
this.info = null;
|
|
167
|
-
this.variables = null;
|
|
168
|
-
if (!data) return;
|
|
169
|
-
if (data.short) this.short = data.short;
|
|
170
|
-
if (data.long) this.long = data.long;
|
|
171
|
-
if (data.info) this.info = data.info;
|
|
172
|
-
if (data.variables) this.variables = getVariables(data.variables);
|
|
173
|
-
}
|
|
174
|
-
description(info) {
|
|
175
|
-
this.info = info;
|
|
176
|
-
return this;
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
|
|
180
798
|
// src/models/Command.ts
|
|
181
799
|
var Command = class {
|
|
182
800
|
constructor(data) {
|
|
@@ -228,8 +846,8 @@ var Command = class {
|
|
|
228
846
|
this.middlewaresArray.push(fn);
|
|
229
847
|
return this;
|
|
230
848
|
}
|
|
231
|
-
middlewares(
|
|
232
|
-
this.middlewaresArray.push(...
|
|
849
|
+
middlewares(fns2) {
|
|
850
|
+
this.middlewaresArray.push(...fns2);
|
|
233
851
|
return this;
|
|
234
852
|
}
|
|
235
853
|
option(short, long, variables, info) {
|
|
@@ -244,9 +862,17 @@ var Command = class {
|
|
|
244
862
|
this.versionString = v;
|
|
245
863
|
return this;
|
|
246
864
|
}
|
|
247
|
-
|
|
865
|
+
buildInfo(info, variables) {
|
|
866
|
+
const hints = variables?.map((v) => v.hint).filter(Boolean) ?? [];
|
|
867
|
+
return [info, ...hints].filter(Boolean).join(" ");
|
|
868
|
+
}
|
|
869
|
+
help(source) {
|
|
870
|
+
const recursive = source?.includes("-r") === true || source?.includes("--recursive") === true;
|
|
871
|
+
this.printHelp(this.name ?? "Program", recursive);
|
|
872
|
+
}
|
|
873
|
+
printHelp(fullName, recursive) {
|
|
248
874
|
const table = [];
|
|
249
|
-
let program =
|
|
875
|
+
let program = fullName;
|
|
250
876
|
if (this.variables) for (const v of this.variables) program += ` ${v.raw}`;
|
|
251
877
|
if (this.optionsArray.length > 0) program += " [...options]";
|
|
252
878
|
table.push({ title: "\nCommand", info: program, data: [] });
|
|
@@ -260,7 +886,7 @@ var Command = class {
|
|
|
260
886
|
if (opt.short && opt.long) name += ", ";
|
|
261
887
|
if (opt.long) name += `--${opt.long}`;
|
|
262
888
|
if (opt.variables) for (const v of opt.variables) name += ` ${v.raw}`;
|
|
263
|
-
section.data.push([name, opt.info
|
|
889
|
+
section.data.push([name, this.buildInfo(opt.info, opt.variables)]);
|
|
264
890
|
}
|
|
265
891
|
table.push(section);
|
|
266
892
|
}
|
|
@@ -269,7 +895,7 @@ var Command = class {
|
|
|
269
895
|
for (const cmd of this.commandsArray) {
|
|
270
896
|
let name = cmd.name ?? "";
|
|
271
897
|
if (cmd.variables) for (const v of cmd.variables) name += ` ${v.raw}`;
|
|
272
|
-
section.data.push([name, cmd.info
|
|
898
|
+
section.data.push([name, this.buildInfo(cmd.info, cmd.variables)]);
|
|
273
899
|
}
|
|
274
900
|
table.push(section);
|
|
275
901
|
}
|
|
@@ -283,7 +909,8 @@ var Command = class {
|
|
|
283
909
|
}
|
|
284
910
|
const lines = [];
|
|
285
911
|
for (const section of table) {
|
|
286
|
-
|
|
912
|
+
const styled = typeof config.color === "number" ? cosmetic.xterm(config.color) : config.color.startsWith("#") ? cosmetic.hex(config.color) : cosmetic[config.color];
|
|
913
|
+
lines.push(section.title ? styled.underline.encoder(section.title) : "");
|
|
287
914
|
if (section.info) lines.push(section.info);
|
|
288
915
|
for (const row of section.data) {
|
|
289
916
|
let line = "";
|
|
@@ -296,18 +923,28 @@ var Command = class {
|
|
|
296
923
|
lines.push("");
|
|
297
924
|
}
|
|
298
925
|
for (const line of lines) console.log(line);
|
|
926
|
+
if (recursive) {
|
|
927
|
+
for (const cmd of this.commandsArray) {
|
|
928
|
+
cmd.printHelp(`${fullName} ${cmd.name ?? ""}`, true);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
299
931
|
}
|
|
300
|
-
async parse(
|
|
301
|
-
const array = [...
|
|
932
|
+
async parse(input2) {
|
|
933
|
+
const array = [...input2];
|
|
302
934
|
array.splice(0, 2);
|
|
303
935
|
let command2 = this;
|
|
304
936
|
const options = { _source: Array.from(array) };
|
|
937
|
+
const ddIdx = array.indexOf("--");
|
|
938
|
+
if (ddIdx !== -1) {
|
|
939
|
+
options._ = array.splice(ddIdx + 1);
|
|
940
|
+
array.splice(ddIdx, 1);
|
|
941
|
+
}
|
|
305
942
|
while (array.length) {
|
|
306
943
|
if (!array.includes("help")) {
|
|
307
|
-
Object.assign(options, findOptions(array, command2));
|
|
308
|
-
const cmdVars = findCommandVariables(array, command2);
|
|
944
|
+
Object.assign(options, await findOptions(array, command2));
|
|
945
|
+
const cmdVars = await findCommandVariables(array, command2);
|
|
309
946
|
if (cmdVars) Object.assign(options, cmdVars);
|
|
310
|
-
Object.assign(options, findOptions(array, command2));
|
|
947
|
+
Object.assign(options, await findOptions(array, command2));
|
|
311
948
|
}
|
|
312
949
|
if (array.length) {
|
|
313
950
|
if (!array.includes("help")) {
|
|
@@ -328,6 +965,14 @@ var Command = class {
|
|
|
328
965
|
command2 = next;
|
|
329
966
|
}
|
|
330
967
|
}
|
|
968
|
+
for (const opt of command2.optionsArray) {
|
|
969
|
+
if (!opt.long || !opt.variables) continue;
|
|
970
|
+
for (const v of opt.variables) {
|
|
971
|
+
if (v.default !== null && !(opt.long in options)) {
|
|
972
|
+
options[opt.long] = coerce(v.default, v.type, v.enum, v.min, v.max);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
331
976
|
for (const mw of command2.middlewaresArray) await mw(options);
|
|
332
977
|
if (command2.actionFunction) return command2.actionFunction(options);
|
|
333
978
|
if (options._source.length === 2) return command2.help(options._source);
|
|
@@ -335,59 +980,1814 @@ var Command = class {
|
|
|
335
980
|
}
|
|
336
981
|
};
|
|
337
982
|
|
|
338
|
-
// src/models/
|
|
339
|
-
var
|
|
340
|
-
|
|
341
|
-
|
|
983
|
+
// src/models/Bar.ts
|
|
984
|
+
var Bar = class {
|
|
985
|
+
constructor(options = {}) {
|
|
986
|
+
// used by MultiBar — not intended for direct external use
|
|
987
|
+
this._isManaged = false;
|
|
988
|
+
this._managedFinalLine = null;
|
|
989
|
+
this._colors = [];
|
|
990
|
+
this._parsedColors = [];
|
|
991
|
+
this._dimmedColors = [];
|
|
992
|
+
this._bgColors = [];
|
|
993
|
+
this._parsedBgColors = [];
|
|
994
|
+
this._colorOffset = 0;
|
|
995
|
+
this._shimmerPhase = 0;
|
|
996
|
+
this._completed = false;
|
|
997
|
+
this._resizeListener = null;
|
|
998
|
+
this._cleanupDeregister = null;
|
|
999
|
+
this._total = null;
|
|
1000
|
+
this._tickCount = 0;
|
|
1001
|
+
this._startTime = null;
|
|
1002
|
+
this._etaSuffix = "";
|
|
1003
|
+
this.running = false;
|
|
1004
|
+
this.forwardMotion = true;
|
|
1005
|
+
this._autoLength = options.length === void 0;
|
|
1006
|
+
this.length = options.length ?? process.stdout.columns ?? 80;
|
|
1007
|
+
this.prefixString = options.prefix ?? "[";
|
|
1008
|
+
this.suffixString = options.suffix ?? "]";
|
|
1009
|
+
this.character = options.character ?? "\u2500\u2500";
|
|
1010
|
+
this.beforeEmpty = options.before ?? " ";
|
|
1011
|
+
this.afterEmpty = options.after ?? " ";
|
|
1012
|
+
this.position = 1;
|
|
1013
|
+
this.interval = options.interval ?? 35;
|
|
1014
|
+
this.mode = options.mode ?? "bounce";
|
|
1015
|
+
this.progress = options.progress;
|
|
1016
|
+
this.colorFill = options.colorFill ?? false;
|
|
1017
|
+
this.colorCycle = options.colorCycle ?? 0.5;
|
|
1018
|
+
this.shimmer = options.shimmer ?? 0;
|
|
1019
|
+
this.text = options.text ?? "";
|
|
1020
|
+
this.reverse = options.reverse ?? false;
|
|
1021
|
+
this.onBounce = options.onBounce;
|
|
1022
|
+
this.onLoop = options.onLoop;
|
|
1023
|
+
this.onComplete = options.onComplete;
|
|
1024
|
+
this.colors = options.colors ?? ["#c026d3", "#e879f9"];
|
|
1025
|
+
this.bgColors = options.bgColors ?? [];
|
|
1026
|
+
this._successColor = options.successColor ?? GREEN;
|
|
1027
|
+
this._failColor = options.failColor ?? RED;
|
|
1028
|
+
this._warnColor = options.warnColor ?? YELLOW;
|
|
1029
|
+
this._infoColor = options.infoColor ?? BLUE;
|
|
1030
|
+
this._glyphs = options.glyphs ?? true;
|
|
1031
|
+
this._showRate = options.showRate ?? false;
|
|
1032
|
+
this._showEta = options.showEta ?? false;
|
|
1033
|
+
this._rateUnit = options.rateUnit ?? "";
|
|
342
1034
|
}
|
|
343
|
-
|
|
344
|
-
|
|
1035
|
+
get colors() {
|
|
1036
|
+
return this._colors;
|
|
345
1037
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
1038
|
+
set colors(value) {
|
|
1039
|
+
this._colors = value;
|
|
1040
|
+
this._parsedColors = value.length > 1 ? value.map(parseHex) : [];
|
|
1041
|
+
this._dimmedColors = this._parsedColors.map(dimColor);
|
|
350
1042
|
}
|
|
351
|
-
|
|
352
|
-
return
|
|
1043
|
+
get bgColors() {
|
|
1044
|
+
return this._bgColors;
|
|
353
1045
|
}
|
|
354
|
-
|
|
355
|
-
|
|
1046
|
+
set bgColors(value) {
|
|
1047
|
+
this._bgColors = value;
|
|
1048
|
+
this._parsedBgColors = value.length > 1 ? value.map(parseHex) : [];
|
|
356
1049
|
}
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
|
|
1050
|
+
set prefix(string) {
|
|
1051
|
+
if (stringLength(string) > stringLength(this.prefixString)) {
|
|
1052
|
+
this.position -= stringLength(string) - 1;
|
|
1053
|
+
if (this.position < 1) this.position = 1;
|
|
1054
|
+
} else {
|
|
1055
|
+
this.position += stringLength(this.prefixString) - 1;
|
|
1056
|
+
}
|
|
1057
|
+
this.prefixString = string;
|
|
1058
|
+
}
|
|
1059
|
+
set suffix(string) {
|
|
1060
|
+
const length = this.length - stringLength(this.prefixString) - stringLength(this.character) - stringLength(string);
|
|
1061
|
+
if (this.position > length) {
|
|
1062
|
+
this.position = length;
|
|
1063
|
+
if (this.forwardMotion) this.forwardMotion = false;
|
|
1064
|
+
}
|
|
1065
|
+
this.suffixString = string;
|
|
1066
|
+
}
|
|
1067
|
+
set before(string) {
|
|
1068
|
+
this.beforeEmpty = stringLength(string) > 1 ? string.charAt(0) : string;
|
|
1069
|
+
}
|
|
1070
|
+
set after(string) {
|
|
1071
|
+
this.afterEmpty = stringLength(string) > 1 ? string.charAt(0) : string;
|
|
1072
|
+
}
|
|
1073
|
+
set empty(string) {
|
|
1074
|
+
const char = stringLength(string) > 1 ? string.charAt(0) : string;
|
|
1075
|
+
this.beforeEmpty = char;
|
|
1076
|
+
this.afterEmpty = char;
|
|
1077
|
+
}
|
|
1078
|
+
start() {
|
|
1079
|
+
if (this._isManaged) return;
|
|
1080
|
+
if (!process.stdout.isTTY) return;
|
|
1081
|
+
this.running = true;
|
|
1082
|
+
process.stdout.write(HIDE_CURSOR);
|
|
1083
|
+
this._cleanupDeregister = registerCleanup(() => {
|
|
1084
|
+
this.running = false;
|
|
1085
|
+
if (this._resizeListener) {
|
|
1086
|
+
process.stdout.off("resize", this._resizeListener);
|
|
1087
|
+
this._resizeListener = null;
|
|
1088
|
+
}
|
|
1089
|
+
process.stdout.clearLine?.(0);
|
|
1090
|
+
process.stdout.write(SHOW_CURSOR);
|
|
1091
|
+
});
|
|
1092
|
+
if (this._autoLength) {
|
|
1093
|
+
this._resizeListener = () => {
|
|
1094
|
+
this.length = process.stdout.columns ?? 80;
|
|
1095
|
+
process.stdout.write("\x1B[0J");
|
|
1096
|
+
};
|
|
1097
|
+
process.stdout.on("resize", this._resizeListener);
|
|
1098
|
+
}
|
|
1099
|
+
this.run();
|
|
1100
|
+
}
|
|
1101
|
+
stop(message) {
|
|
1102
|
+
this.running = false;
|
|
1103
|
+
if (this._isManaged) {
|
|
1104
|
+
this._managedFinalLine = message ?? "";
|
|
1105
|
+
return this;
|
|
1106
|
+
}
|
|
1107
|
+
this._cleanupDeregister?.();
|
|
1108
|
+
this._cleanupDeregister = null;
|
|
1109
|
+
if (process.stdout.isTTY) {
|
|
1110
|
+
if (this._resizeListener) {
|
|
1111
|
+
process.stdout.off("resize", this._resizeListener);
|
|
1112
|
+
this._resizeListener = null;
|
|
1113
|
+
}
|
|
1114
|
+
this.clear();
|
|
1115
|
+
process.stdout.write(SHOW_CURSOR);
|
|
1116
|
+
}
|
|
1117
|
+
if (message) process.stdout.write(`${message}
|
|
1118
|
+
`);
|
|
1119
|
+
return this;
|
|
1120
|
+
}
|
|
1121
|
+
message(string) {
|
|
1122
|
+
this.text = string;
|
|
1123
|
+
return this;
|
|
1124
|
+
}
|
|
1125
|
+
track(total, options) {
|
|
1126
|
+
this._total = total;
|
|
1127
|
+
this._tickCount = 0;
|
|
1128
|
+
this._startTime = Date.now();
|
|
1129
|
+
this._etaSuffix = "";
|
|
1130
|
+
if (options?.unit !== void 0) this._rateUnit = options.unit;
|
|
1131
|
+
if (options?.showRate !== void 0) this._showRate = options.showRate;
|
|
1132
|
+
if (options?.showEta !== void 0) this._showEta = options.showEta;
|
|
1133
|
+
if (!this._showRate && !this._showEta) {
|
|
1134
|
+
this._showRate = true;
|
|
1135
|
+
this._showEta = true;
|
|
1136
|
+
}
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
tick(n = 1) {
|
|
1140
|
+
this._tickCount += n;
|
|
1141
|
+
if (this._total !== null && this._startTime !== null) {
|
|
1142
|
+
this.progress = Math.min(1, this._tickCount / this._total);
|
|
1143
|
+
const elapsed = (Date.now() - this._startTime) / 1e3;
|
|
1144
|
+
const rate = elapsed > 0 ? this._tickCount / elapsed : 0;
|
|
1145
|
+
const remaining = this._total - this._tickCount;
|
|
1146
|
+
const parts = [];
|
|
1147
|
+
if (this._showRate) {
|
|
1148
|
+
const rateStr = rate >= 1e3 ? `${(rate / 1e3).toFixed(1)}k` : rate >= 1 ? rate.toFixed(1) : rate.toFixed(2);
|
|
1149
|
+
parts.push(`${rateStr}/s${this._rateUnit ? ` ${this._rateUnit}` : ""}`);
|
|
1150
|
+
}
|
|
1151
|
+
if (this._showEta && remaining > 0) {
|
|
1152
|
+
const eta = rate > 0 ? remaining / rate : 0;
|
|
1153
|
+
const etaStr = eta >= 3600 ? `${Math.floor(eta / 3600)}h${Math.floor(eta % 3600 / 60)}m` : eta >= 60 ? `${Math.floor(eta / 60)}m${Math.floor(eta % 60)}s` : `${Math.ceil(eta)}s`;
|
|
1154
|
+
parts.push(`ETA ${etaStr}`);
|
|
1155
|
+
}
|
|
1156
|
+
this._etaSuffix = parts.join(" \xB7 ");
|
|
1157
|
+
}
|
|
1158
|
+
return this;
|
|
1159
|
+
}
|
|
1160
|
+
get rate() {
|
|
1161
|
+
if (this._startTime === null || this._tickCount === 0) return 0;
|
|
1162
|
+
const elapsed = (Date.now() - this._startTime) / 1e3;
|
|
1163
|
+
return elapsed > 0 ? this._tickCount / elapsed : 0;
|
|
1164
|
+
}
|
|
1165
|
+
get eta() {
|
|
1166
|
+
if (this._total === null || this.rate === 0) return 0;
|
|
1167
|
+
return Math.max(0, (this._total - this._tickCount) / this.rate);
|
|
1168
|
+
}
|
|
1169
|
+
succeed(string) {
|
|
1170
|
+
this.running = false;
|
|
1171
|
+
if (this._isManaged) {
|
|
1172
|
+
const glyph = this._glyphs ? colorText(this._successColor, "\u2714") + " " : "";
|
|
1173
|
+
this._managedFinalLine = `${glyph}${string ?? ""}`;
|
|
1174
|
+
return this;
|
|
1175
|
+
}
|
|
1176
|
+
this._cleanupDeregister?.();
|
|
1177
|
+
this._cleanupDeregister = null;
|
|
1178
|
+
if (process.stdout.isTTY) {
|
|
1179
|
+
if (this._resizeListener) {
|
|
1180
|
+
process.stdout.off("resize", this._resizeListener);
|
|
1181
|
+
this._resizeListener = null;
|
|
1182
|
+
}
|
|
1183
|
+
this.clear();
|
|
1184
|
+
process.stdout.write(`${SHOW_CURSOR}${colorText(this._successColor, "\u2714")}${string ? ` ${string}` : ""}
|
|
1185
|
+
`);
|
|
1186
|
+
} else {
|
|
1187
|
+
process.stdout.write(`${this._glyphs ? `\u2714${string ? ` ${string}` : ""}` : string ?? ""}
|
|
1188
|
+
`);
|
|
1189
|
+
}
|
|
1190
|
+
return this;
|
|
1191
|
+
}
|
|
1192
|
+
fail(string) {
|
|
1193
|
+
this.running = false;
|
|
1194
|
+
if (this._isManaged) {
|
|
1195
|
+
const glyph = this._glyphs ? colorText(this._failColor, "\u2716") + " " : "";
|
|
1196
|
+
this._managedFinalLine = `${glyph}${string ?? ""}`;
|
|
1197
|
+
return this;
|
|
1198
|
+
}
|
|
1199
|
+
this._cleanupDeregister?.();
|
|
1200
|
+
this._cleanupDeregister = null;
|
|
1201
|
+
if (process.stdout.isTTY) {
|
|
1202
|
+
if (this._resizeListener) {
|
|
1203
|
+
process.stdout.off("resize", this._resizeListener);
|
|
1204
|
+
this._resizeListener = null;
|
|
1205
|
+
}
|
|
1206
|
+
this.clear();
|
|
1207
|
+
process.stdout.write(`${SHOW_CURSOR}${colorText(this._failColor, "\u2716")}${string ? ` ${string}` : ""}
|
|
1208
|
+
`);
|
|
1209
|
+
} else {
|
|
1210
|
+
process.stdout.write(`${this._glyphs ? `\u2716${string ? ` ${string}` : ""}` : string ?? ""}
|
|
1211
|
+
`);
|
|
1212
|
+
}
|
|
1213
|
+
return this;
|
|
1214
|
+
}
|
|
1215
|
+
warn(string) {
|
|
1216
|
+
this.running = false;
|
|
1217
|
+
if (this._isManaged) {
|
|
1218
|
+
const glyph = this._glyphs ? colorText(this._warnColor, "\u26A0") + " " : "";
|
|
1219
|
+
this._managedFinalLine = `${glyph}${string ?? ""}`;
|
|
1220
|
+
return this;
|
|
1221
|
+
}
|
|
1222
|
+
this._cleanupDeregister?.();
|
|
1223
|
+
this._cleanupDeregister = null;
|
|
1224
|
+
if (process.stdout.isTTY) {
|
|
1225
|
+
if (this._resizeListener) {
|
|
1226
|
+
process.stdout.off("resize", this._resizeListener);
|
|
1227
|
+
this._resizeListener = null;
|
|
1228
|
+
}
|
|
1229
|
+
this.clear();
|
|
1230
|
+
process.stdout.write(`${SHOW_CURSOR}${colorText(this._warnColor, "\u26A0")}${string ? ` ${string}` : ""}
|
|
1231
|
+
`);
|
|
1232
|
+
} else {
|
|
1233
|
+
process.stdout.write(`${this._glyphs ? `\u26A0${string ? ` ${string}` : ""}` : string ?? ""}
|
|
1234
|
+
`);
|
|
1235
|
+
}
|
|
1236
|
+
return this;
|
|
1237
|
+
}
|
|
1238
|
+
info(string) {
|
|
1239
|
+
this.running = false;
|
|
1240
|
+
if (this._isManaged) {
|
|
1241
|
+
const glyph = this._glyphs ? colorText(this._infoColor, "\u2139") + " " : "";
|
|
1242
|
+
this._managedFinalLine = `${glyph}${string ?? ""}`;
|
|
1243
|
+
return this;
|
|
1244
|
+
}
|
|
1245
|
+
this._cleanupDeregister?.();
|
|
1246
|
+
this._cleanupDeregister = null;
|
|
1247
|
+
if (process.stdout.isTTY) {
|
|
1248
|
+
if (this._resizeListener) {
|
|
1249
|
+
process.stdout.off("resize", this._resizeListener);
|
|
1250
|
+
this._resizeListener = null;
|
|
1251
|
+
}
|
|
1252
|
+
this.clear();
|
|
1253
|
+
process.stdout.write(`${SHOW_CURSOR}${colorText(this._infoColor, "\u2139")}${string ? ` ${string}` : ""}
|
|
1254
|
+
`);
|
|
1255
|
+
} else {
|
|
1256
|
+
process.stdout.write(`${this._glyphs ? `\u2139${string ? ` ${string}` : ""}` : string ?? ""}
|
|
1257
|
+
`);
|
|
1258
|
+
}
|
|
1259
|
+
return this;
|
|
1260
|
+
}
|
|
1261
|
+
// Returns the rendered bar line string for the current animation frame.
|
|
1262
|
+
// width overrides this.length for use by MultiBar.
|
|
1263
|
+
renderLine(width) {
|
|
1264
|
+
return this.buildLine(width);
|
|
1265
|
+
}
|
|
1266
|
+
// Advances animation state (color cycle, shimmer, indeterminate position).
|
|
1267
|
+
// Called by MultiBar after reading renderLine() each tick.
|
|
1268
|
+
advanceFrame() {
|
|
1269
|
+
const totalLength = this.length;
|
|
1270
|
+
const textReserved = this.text ? stringLength(this.text) + 1 : 0;
|
|
1271
|
+
const suffixReserved = this._etaSuffix ? stringLength(this._etaSuffix) + 1 : 0;
|
|
1272
|
+
const length = Math.max(1, totalLength - textReserved - suffixReserved - stringLength(this.prefixString) - stringLength(this.character) - stringLength(this.suffixString));
|
|
1273
|
+
if (this.progress === void 0) this.advanceIndeterminate(length);
|
|
1274
|
+
if (this.colorCycle > 0) this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
|
|
1275
|
+
if (this.shimmer > 0) this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
|
|
1276
|
+
}
|
|
1277
|
+
clear() {
|
|
1278
|
+
process.stdout.clearLine?.(0);
|
|
1279
|
+
}
|
|
1280
|
+
effectiveT(t) {
|
|
1281
|
+
if (this.colorCycle === 0) return t;
|
|
1282
|
+
return ((t + this._colorOffset) % 1 + 1) % 1;
|
|
1283
|
+
}
|
|
1284
|
+
coloredChar(colors, code, t) {
|
|
1285
|
+
const et = this.effectiveT(t);
|
|
1286
|
+
const base2 = interpolateColor(colors, et);
|
|
1287
|
+
const shimmered = applyShimmer(base2, t, this._shimmerPhase, this.shimmer);
|
|
1288
|
+
return formatColor(code, shimmered);
|
|
1289
|
+
}
|
|
1290
|
+
colorChar(t) {
|
|
1291
|
+
const fg = this._parsedColors.length >= 2 ? this.coloredChar(this._parsedColors, 38, t) : "";
|
|
1292
|
+
const bg = this._parsedBgColors.length >= 2 ? this.coloredChar(this._parsedBgColors, 48, t) : "";
|
|
1293
|
+
return fg || bg ? fg + bg + this.character + RESET : this.character;
|
|
1294
|
+
}
|
|
1295
|
+
colorFillChar(char, t) {
|
|
1296
|
+
const fg = this.colorFill && this._dimmedColors.length >= 2 ? this.coloredChar(this._dimmedColors, 38, t) : "";
|
|
1297
|
+
const bg = this._parsedBgColors.length >= 2 ? this.coloredChar(this._parsedBgColors, 48, t) : "";
|
|
1298
|
+
return fg || bg ? fg + bg + char + RESET : char;
|
|
1299
|
+
}
|
|
1300
|
+
buildDeterminate(length) {
|
|
1301
|
+
const charWidth = stringLength(this.character);
|
|
1302
|
+
const clamped = Math.max(0, Math.min(1, this.progress));
|
|
1303
|
+
const filled = Math.round(clamped * length);
|
|
1304
|
+
let working = this.prefixString;
|
|
1305
|
+
for (let i = 0; i < filled; i++) {
|
|
1306
|
+
const t = length > 1 ? i / (length - 1) : 0;
|
|
1307
|
+
working += this.colorChar(t);
|
|
1308
|
+
}
|
|
1309
|
+
for (let i = filled; i < length; i++) {
|
|
1310
|
+
const t = length > 1 ? i / (length - 1) : 0;
|
|
1311
|
+
for (let j = 0; j < charWidth; j++) {
|
|
1312
|
+
working += this.colorFillChar(this.afterEmpty, t);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
working += this.suffixString;
|
|
1316
|
+
if (clamped >= 1 && !this._completed) {
|
|
1317
|
+
this._completed = true;
|
|
1318
|
+
this.onComplete?.();
|
|
1319
|
+
} else if (clamped < 1) {
|
|
1320
|
+
this._completed = false;
|
|
1321
|
+
}
|
|
1322
|
+
return working;
|
|
1323
|
+
}
|
|
1324
|
+
buildIndeterminate(length) {
|
|
1325
|
+
const pos = Math.max(1, Math.min(length, this.position));
|
|
1326
|
+
let working = this.prefixString;
|
|
1327
|
+
let i = 1;
|
|
1328
|
+
while (i < pos) {
|
|
1329
|
+
const t = length > 1 ? (i - 1) / (length - 1) : 0;
|
|
1330
|
+
working += this.colorFillChar(this.beforeEmpty, t);
|
|
1331
|
+
i++;
|
|
1332
|
+
}
|
|
1333
|
+
const charT = length > 1 ? (pos - 1) / (length - 1) : 0;
|
|
1334
|
+
working += this.colorChar(charT);
|
|
1335
|
+
i++;
|
|
1336
|
+
while (i <= length) {
|
|
1337
|
+
const t = length > 1 ? (i - 1) / (length - 1) : 0;
|
|
1338
|
+
working += this.colorFillChar(this.afterEmpty, t);
|
|
1339
|
+
i++;
|
|
1340
|
+
}
|
|
1341
|
+
working += this.suffixString;
|
|
1342
|
+
return working;
|
|
1343
|
+
}
|
|
1344
|
+
advanceIndeterminate(length) {
|
|
1345
|
+
if (this.position > length) {
|
|
1346
|
+
this.position = length;
|
|
1347
|
+
this.forwardMotion = false;
|
|
1348
|
+
}
|
|
1349
|
+
if (this.position < 1) {
|
|
1350
|
+
this.position = 1;
|
|
1351
|
+
this.forwardMotion = true;
|
|
1352
|
+
}
|
|
1353
|
+
if (this.mode === "loop") {
|
|
1354
|
+
this.position++;
|
|
1355
|
+
if (this.position > length) {
|
|
1356
|
+
this.position = 1;
|
|
1357
|
+
this.onLoop?.();
|
|
1358
|
+
}
|
|
1359
|
+
} else if (this.mode === "loop-reverse") {
|
|
1360
|
+
this.position--;
|
|
1361
|
+
if (this.position < 1) {
|
|
1362
|
+
this.position = length;
|
|
1363
|
+
this.onLoop?.();
|
|
1364
|
+
}
|
|
1365
|
+
} else {
|
|
1366
|
+
if (this.forwardMotion) {
|
|
1367
|
+
this.position++;
|
|
1368
|
+
if (this.position >= length) {
|
|
1369
|
+
this.forwardMotion = false;
|
|
1370
|
+
this.onBounce?.();
|
|
1371
|
+
}
|
|
1372
|
+
} else {
|
|
1373
|
+
this.position--;
|
|
1374
|
+
if (this.position <= 1) {
|
|
1375
|
+
this.forwardMotion = true;
|
|
1376
|
+
this.onBounce?.();
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
buildLine(width) {
|
|
1382
|
+
const totalLength = width ?? this.length;
|
|
1383
|
+
const charWidth = stringLength(this.character);
|
|
1384
|
+
const textReserved = this.text ? stringLength(this.text) + 1 : 0;
|
|
1385
|
+
const suffixReserved = this._etaSuffix ? stringLength(this._etaSuffix) + 1 : 0;
|
|
1386
|
+
const available = totalLength - textReserved - suffixReserved - stringLength(this.prefixString) - stringLength(this.suffixString);
|
|
1387
|
+
const length = this.progress !== void 0 ? (
|
|
1388
|
+
// Determinate: every position (filled or empty) is charWidth wide → constant bar width
|
|
1389
|
+
Math.max(1, Math.floor((available - 1) / charWidth))
|
|
1390
|
+
) : (
|
|
1391
|
+
// Indeterminate: one position uses character, rest use 1-char fill (unchanged formula)
|
|
1392
|
+
Math.max(1, available - charWidth)
|
|
1393
|
+
);
|
|
1394
|
+
const working = this.progress !== void 0 ? this.buildDeterminate(length) : this.buildIndeterminate(length);
|
|
1395
|
+
const t = this.text;
|
|
1396
|
+
const suffix = this._etaSuffix ? ` ${this._etaSuffix}` : "";
|
|
1397
|
+
return this.reverse ? t ? `${t} ${working}` : working : t ? `${working} ${t}${suffix}` : `${working}${suffix}`;
|
|
1398
|
+
}
|
|
1399
|
+
run() {
|
|
1400
|
+
process.stdout.write(`${this.buildLine()}\x1B[K\r`);
|
|
1401
|
+
this.advanceFrame();
|
|
1402
|
+
setTimeout(() => {
|
|
1403
|
+
if (this.running) this.run();
|
|
1404
|
+
}, this.interval);
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
Bar.COLORS = {
|
|
1408
|
+
blueRed: ["#0000ff", "#ff0000"],
|
|
1409
|
+
redBlue: ["#ff0000", "#0000ff"],
|
|
1410
|
+
rainbow: ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#8b00ff"],
|
|
1411
|
+
heat: ["#0000ff", "#00ffff", "#ffff00", "#ff0000"],
|
|
1412
|
+
cool: ["#00ffff", "#0000ff", "#8b00ff"],
|
|
1413
|
+
sunset: ["#8b00ff", "#ff0000", "#ff7f00"]
|
|
1414
|
+
};
|
|
1415
|
+
|
|
1416
|
+
// src/models/Chart.ts
|
|
1417
|
+
var Chart_exports = {};
|
|
1418
|
+
__export(Chart_exports, {
|
|
1419
|
+
Bar: () => Bar2,
|
|
1420
|
+
Heatmap: () => Heatmap,
|
|
1421
|
+
Line: () => Line,
|
|
1422
|
+
Scatter: () => Scatter,
|
|
1423
|
+
Sparkline: () => Sparkline,
|
|
1424
|
+
VerticalBar: () => VerticalBar
|
|
1425
|
+
});
|
|
1426
|
+
import Color from "cosmetic";
|
|
1427
|
+
|
|
1428
|
+
// src/utils/padLeft.ts
|
|
1429
|
+
var padLeft = (string, padding) => {
|
|
1430
|
+
while (stringLength(string) < padding) string = ` ${string}`;
|
|
1431
|
+
return string;
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
// src/utils/padRight.ts
|
|
1435
|
+
var padRight = (string, padding) => {
|
|
1436
|
+
while (stringLength(string) < padding) string += " ";
|
|
1437
|
+
return string;
|
|
1438
|
+
};
|
|
1439
|
+
|
|
1440
|
+
// src/models/Chart.ts
|
|
1441
|
+
function formatNum(n) {
|
|
1442
|
+
if (Number.isInteger(n)) return String(n);
|
|
1443
|
+
return parseFloat(n.toFixed(2)).toString();
|
|
1444
|
+
}
|
|
1445
|
+
function applyConfigColor(s) {
|
|
1446
|
+
const c = config.color;
|
|
1447
|
+
if (typeof c === "number") return Color.xterm(c).encoder(s);
|
|
1448
|
+
if (c.startsWith("#")) return Color.hex(c).encoder(s);
|
|
1449
|
+
return Color[c].encoder(s);
|
|
1450
|
+
}
|
|
1451
|
+
function applyPadding(str, paddingX, paddingY) {
|
|
1452
|
+
const lines = str.split("\n");
|
|
1453
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
1454
|
+
const indented = lines.map((l) => " ".repeat(paddingX) + l).join("\n") + "\n";
|
|
1455
|
+
return "\n".repeat(paddingY) + indented + "\n".repeat(paddingY);
|
|
1456
|
+
}
|
|
1457
|
+
var BLOCKS = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
|
|
1458
|
+
var Bar2 = class {
|
|
1459
|
+
constructor(data, options = {}) {
|
|
1460
|
+
this.string = "";
|
|
1461
|
+
const paddingX = options.paddingX ?? 0;
|
|
1462
|
+
const paddingY = options.paddingY ?? 0;
|
|
1463
|
+
let maxKeyLen = 0;
|
|
1464
|
+
let maxValue = 0;
|
|
1465
|
+
let maxValueLen = 0;
|
|
1466
|
+
for (const item of data) {
|
|
1467
|
+
if (!item) continue;
|
|
1468
|
+
if (item.key) maxKeyLen = Math.max(maxKeyLen, stringLength(item.key));
|
|
1469
|
+
maxValue = Math.max(maxValue, item.value);
|
|
1470
|
+
maxValueLen = Math.max(maxValueLen, String(item.value).length);
|
|
1471
|
+
}
|
|
1472
|
+
const cols = options.width ?? process.stdout.columns ?? 80;
|
|
1473
|
+
const available = cols - maxKeyLen - maxValueLen - 3;
|
|
1474
|
+
const scale = maxValue > 0 && available > 0 ? available / maxValue : 0;
|
|
1475
|
+
const encodeKey = (s) => typeof config.color === "number" ? Color.xterm(config.color).encoder(s) : config.color.startsWith("#") ? Color.hex(config.color).encoder(s) : Color[config.color].encoder(s);
|
|
1476
|
+
for (const item of data) {
|
|
1477
|
+
if (!item) {
|
|
1478
|
+
this.string += "\n";
|
|
1479
|
+
continue;
|
|
1480
|
+
}
|
|
1481
|
+
const rawKey = item.key ?? "";
|
|
1482
|
+
const keyPart = (rawKey ? encodeKey(rawKey) : "") + " ".repeat(maxKeyLen - stringLength(rawKey));
|
|
1483
|
+
const barWidth = Math.max(1, Math.floor(item.value * scale));
|
|
1484
|
+
let bar = (item.character ?? " ").repeat(barWidth);
|
|
1485
|
+
bar = item.style ? item.style(bar) : Color.background.white.encoder(bar);
|
|
1486
|
+
this.string += `${keyPart}|${bar} ${item.value}
|
|
1487
|
+
`;
|
|
1488
|
+
}
|
|
1489
|
+
if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
|
|
1490
|
+
}
|
|
1491
|
+
print() {
|
|
1492
|
+
process.stdout.write(this.string);
|
|
1493
|
+
}
|
|
1494
|
+
toString() {
|
|
1495
|
+
return this.string;
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
var VerticalBar = class {
|
|
1499
|
+
constructor(data, options = {}) {
|
|
1500
|
+
this.string = "";
|
|
1501
|
+
const paddingX = options.paddingX ?? 0;
|
|
1502
|
+
const paddingY = options.paddingY ?? 0;
|
|
1503
|
+
const height = options.height ?? 10;
|
|
1504
|
+
const colWidth = options.colWidth ?? (options.width ? Math.max(1, Math.floor(options.width / data.length)) : 2);
|
|
1505
|
+
let maxValue = 0;
|
|
1506
|
+
for (const item of data) {
|
|
1507
|
+
if (item) maxValue = Math.max(maxValue, item.value);
|
|
1508
|
+
}
|
|
1509
|
+
for (let row = height; row >= 1; row--) {
|
|
1510
|
+
let line = "";
|
|
1511
|
+
for (const item of data) {
|
|
1512
|
+
if (!item) {
|
|
1513
|
+
line += " ".repeat(colWidth);
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
const barHeight = maxValue > 0 ? item.value / maxValue * height : 0;
|
|
1517
|
+
const full = Math.floor(barHeight);
|
|
1518
|
+
const frac = barHeight - full;
|
|
1519
|
+
let chars;
|
|
1520
|
+
if (row <= full) {
|
|
1521
|
+
chars = "\u2588".repeat(colWidth);
|
|
1522
|
+
} else if (row === full + 1 && frac > 0) {
|
|
1523
|
+
chars = (BLOCKS[Math.round(frac * 8)] ?? " ").repeat(colWidth);
|
|
1524
|
+
} else {
|
|
1525
|
+
chars = " ".repeat(colWidth);
|
|
1526
|
+
}
|
|
1527
|
+
if (item.style && chars.trim()) chars = item.style(chars);
|
|
1528
|
+
line += chars;
|
|
1529
|
+
}
|
|
1530
|
+
this.string += line + "\n";
|
|
1531
|
+
}
|
|
1532
|
+
this.string += "\u2500".repeat(data.length * colWidth) + "\n";
|
|
1533
|
+
if (data.some((item) => item?.key)) {
|
|
1534
|
+
const encodeLabel = (s) => typeof config.color === "number" ? Color.xterm(config.color).encoder(s) : config.color.startsWith("#") ? Color.hex(config.color).encoder(s) : Color[config.color].encoder(s);
|
|
1535
|
+
let labels = "";
|
|
1536
|
+
for (const item of data) {
|
|
1537
|
+
if (!item?.key) {
|
|
1538
|
+
labels += " ".repeat(colWidth);
|
|
1539
|
+
} else {
|
|
1540
|
+
const key = item.key.length > colWidth ? item.key.slice(0, colWidth) : item.key;
|
|
1541
|
+
labels += encodeLabel(key) + " ".repeat(colWidth - key.length);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
this.string += labels + "\n";
|
|
1545
|
+
}
|
|
1546
|
+
if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
|
|
1547
|
+
}
|
|
1548
|
+
print() {
|
|
1549
|
+
process.stdout.write(this.string);
|
|
1550
|
+
}
|
|
1551
|
+
toString() {
|
|
1552
|
+
return this.string;
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
var Heatmap = class {
|
|
1556
|
+
constructor(data, options = {}) {
|
|
1557
|
+
this.string = "";
|
|
1558
|
+
const paddingX = options.paddingX ?? 0;
|
|
1559
|
+
const paddingY = options.paddingY ?? 0;
|
|
1560
|
+
const cellWidth = options.cellWidth ?? 2;
|
|
1561
|
+
const parsedColors = (options.colors ?? ["#0000ff", "#ff0000"]).map(parseHex);
|
|
1562
|
+
let min = options.min;
|
|
1563
|
+
let max = options.max;
|
|
1564
|
+
for (const row of data) {
|
|
1565
|
+
for (const val of row) {
|
|
1566
|
+
if (min === void 0 || val < min) min = val;
|
|
1567
|
+
if (max === void 0 || val > max) max = val;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
const lo = min ?? 0;
|
|
1571
|
+
const hi = max ?? 1;
|
|
1572
|
+
const range = hi - lo || 1;
|
|
1573
|
+
const rowLabelWidth = options.rowLabels ? Math.max(...options.rowLabels.map((l) => stringLength(l))) + 1 : 0;
|
|
1574
|
+
if (options.colLabels) {
|
|
1575
|
+
this.string += " ".repeat(rowLabelWidth);
|
|
1576
|
+
for (const label of options.colLabels) {
|
|
1577
|
+
this.string += label.length > cellWidth ? label.slice(0, cellWidth) : label.padEnd(cellWidth);
|
|
1578
|
+
}
|
|
1579
|
+
this.string += "\n";
|
|
1580
|
+
}
|
|
1581
|
+
for (let r = 0; r < data.length; r++) {
|
|
1582
|
+
if (options.rowLabels) {
|
|
1583
|
+
this.string += padRight(options.rowLabels[r] ?? "", rowLabelWidth - 1) + " ";
|
|
1584
|
+
}
|
|
1585
|
+
for (const val of data[r]) {
|
|
1586
|
+
const t = (val - lo) / range;
|
|
1587
|
+
const color = interpolateColor(parsedColors, t);
|
|
1588
|
+
this.string += `${formatColor(48, color)}${" ".repeat(cellWidth)}${RESET}`;
|
|
1589
|
+
}
|
|
1590
|
+
this.string += "\n";
|
|
1591
|
+
}
|
|
1592
|
+
if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
|
|
1593
|
+
}
|
|
1594
|
+
print() {
|
|
1595
|
+
process.stdout.write(this.string);
|
|
1596
|
+
}
|
|
1597
|
+
toString() {
|
|
1598
|
+
return this.string;
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
var Scatter = class {
|
|
1602
|
+
constructor(data, options = {}) {
|
|
1603
|
+
this.string = "";
|
|
1604
|
+
const paddingX = options.paddingX ?? 0;
|
|
1605
|
+
const paddingY = options.paddingY ?? 0;
|
|
1606
|
+
const defaultChar = options.character ?? "\u2022";
|
|
1607
|
+
const showAxes = options.axes ?? true;
|
|
1608
|
+
let xMin = options.xMin ?? (data.length ? Math.min(...data.map((p) => p.x)) : 0);
|
|
1609
|
+
let xMax = options.xMax ?? (data.length ? Math.max(...data.map((p) => p.x)) : 1);
|
|
1610
|
+
let yMin = options.yMin ?? (data.length ? Math.min(...data.map((p) => p.y)) : 0);
|
|
1611
|
+
let yMax = options.yMax ?? (data.length ? Math.max(...data.map((p) => p.y)) : 1);
|
|
1612
|
+
if (xMin === xMax) {
|
|
1613
|
+
xMin -= 1;
|
|
1614
|
+
xMax += 1;
|
|
1615
|
+
}
|
|
1616
|
+
if (yMin === yMax) {
|
|
1617
|
+
yMin -= 1;
|
|
1618
|
+
yMax += 1;
|
|
1619
|
+
}
|
|
1620
|
+
const totalWidth = options.width ?? process.stdout.columns ?? 80;
|
|
1621
|
+
const totalHeight = options.height ?? 20;
|
|
1622
|
+
const plotWidth = showAxes ? Math.max(1, totalWidth - Math.max(formatNum(yMax).length, formatNum(yMin).length, formatNum((yMin + yMax) / 2).length) - 1) : totalWidth;
|
|
1623
|
+
const plotHeight = showAxes ? Math.max(1, totalHeight - 2) : totalHeight;
|
|
1624
|
+
const grid = Array.from({ length: plotHeight }, () => Array(plotWidth).fill(" "));
|
|
1625
|
+
for (const point of data) {
|
|
1626
|
+
const col = Math.round((point.x - xMin) / (xMax - xMin) * (plotWidth - 1));
|
|
1627
|
+
const row = plotHeight - 1 - Math.round((point.y - yMin) / (yMax - yMin) * (plotHeight - 1));
|
|
1628
|
+
if (col >= 0 && col < plotWidth && row >= 0 && row < plotHeight) {
|
|
1629
|
+
const char = point.character ?? defaultChar;
|
|
1630
|
+
grid[row][col] = point.style ? point.style(char) : char;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
if (showAxes) {
|
|
1634
|
+
const yAxisWidth = Math.max(formatNum(yMax).length, formatNum(yMin).length, formatNum((yMin + yMax) / 2).length);
|
|
1635
|
+
const midRow = Math.floor((plotHeight - 1) / 2);
|
|
1636
|
+
for (let r = 0; r < plotHeight; r++) {
|
|
1637
|
+
let yLabel = "";
|
|
1638
|
+
if (r === 0) yLabel = formatNum(yMax);
|
|
1639
|
+
else if (r === midRow) yLabel = formatNum((yMin + yMax) / 2);
|
|
1640
|
+
else if (r === plotHeight - 1) yLabel = formatNum(yMin);
|
|
1641
|
+
const coloredLabel = yLabel ? applyConfigColor(yLabel) : "";
|
|
1642
|
+
this.string += padLeft(coloredLabel, yAxisWidth) + "\u2502" + grid[r].join("") + "\n";
|
|
1643
|
+
}
|
|
1644
|
+
this.string += " ".repeat(yAxisWidth) + "\u2514" + "\u2500".repeat(plotWidth) + "\n";
|
|
1645
|
+
const xMinRaw = formatNum(xMin);
|
|
1646
|
+
const xMidRaw = formatNum((xMin + xMax) / 2);
|
|
1647
|
+
const xMaxRaw = formatNum(xMax);
|
|
1648
|
+
const midCol = Math.floor(plotWidth / 2) - Math.floor(xMidRaw.length / 2);
|
|
1649
|
+
const gap1 = Math.max(0, midCol - xMinRaw.length);
|
|
1650
|
+
const gap2 = Math.max(0, plotWidth - xMinRaw.length - gap1 - xMidRaw.length - xMaxRaw.length);
|
|
1651
|
+
this.string += " ".repeat(yAxisWidth + 1) + applyConfigColor(xMinRaw) + " ".repeat(gap1) + applyConfigColor(xMidRaw) + " ".repeat(gap2) + applyConfigColor(xMaxRaw) + "\n";
|
|
1652
|
+
} else {
|
|
1653
|
+
for (const row of grid) {
|
|
1654
|
+
this.string += row.join("") + "\n";
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
|
|
1658
|
+
}
|
|
1659
|
+
print() {
|
|
1660
|
+
process.stdout.write(this.string);
|
|
1661
|
+
}
|
|
1662
|
+
toString() {
|
|
1663
|
+
return this.string;
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
var Line = class {
|
|
1667
|
+
constructor(data, options = {}) {
|
|
1668
|
+
this.string = "";
|
|
1669
|
+
const paddingX = options.paddingX ?? 0;
|
|
1670
|
+
const paddingY = options.paddingY ?? 0;
|
|
1671
|
+
const defaultChar = options.character ?? "\u2022";
|
|
1672
|
+
const showAxes = options.axes ?? true;
|
|
1673
|
+
const fill = options.fill ?? false;
|
|
1674
|
+
let xMin = options.xMin ?? (data.length ? Math.min(...data.map((p) => p.x)) : 0);
|
|
1675
|
+
let xMax = options.xMax ?? (data.length ? Math.max(...data.map((p) => p.x)) : 1);
|
|
1676
|
+
let yMin = options.yMin ?? (data.length ? Math.min(...data.map((p) => p.y)) : 0);
|
|
1677
|
+
let yMax = options.yMax ?? (data.length ? Math.max(...data.map((p) => p.y)) : 1);
|
|
1678
|
+
if (xMin === xMax) {
|
|
1679
|
+
xMin -= 1;
|
|
1680
|
+
xMax += 1;
|
|
1681
|
+
}
|
|
1682
|
+
if (yMin === yMax) {
|
|
1683
|
+
yMin -= 1;
|
|
1684
|
+
yMax += 1;
|
|
1685
|
+
}
|
|
1686
|
+
const totalWidth = options.width ?? process.stdout.columns ?? 80;
|
|
1687
|
+
const totalHeight = options.height ?? 20;
|
|
1688
|
+
const yAxisWidth = showAxes ? Math.max(formatNum(yMax).length, formatNum(yMin).length, formatNum((yMin + yMax) / 2).length) : 0;
|
|
1689
|
+
const plotWidth = showAxes ? Math.max(1, totalWidth - yAxisWidth - 1) : totalWidth;
|
|
1690
|
+
const plotHeight = showAxes ? Math.max(1, totalHeight - 2) : totalHeight;
|
|
1691
|
+
const grid = Array.from({ length: plotHeight }, () => Array(plotWidth).fill(" "));
|
|
1692
|
+
const sorted = [...data].sort((a, b) => a.x - b.x);
|
|
1693
|
+
const xRange = xMax - xMin;
|
|
1694
|
+
const yRange = yMax - yMin;
|
|
1695
|
+
for (let col = 0; col < plotWidth; col++) {
|
|
1696
|
+
const xVal = xMin + col / Math.max(1, plotWidth - 1) * xRange;
|
|
1697
|
+
let yVal = null;
|
|
1698
|
+
let pointStyle;
|
|
1699
|
+
for (let pi = 0; pi < sorted.length; pi++) {
|
|
1700
|
+
const p = sorted[pi];
|
|
1701
|
+
const next = sorted[pi + 1];
|
|
1702
|
+
if (next === void 0) {
|
|
1703
|
+
if (Math.abs(p.x - xVal) <= xRange / plotWidth) {
|
|
1704
|
+
yVal = p.y;
|
|
1705
|
+
pointStyle = p.style;
|
|
1706
|
+
}
|
|
1707
|
+
break;
|
|
1708
|
+
}
|
|
1709
|
+
if (p.x <= xVal && next.x >= xVal) {
|
|
1710
|
+
const t = next.x === p.x ? 0 : (xVal - p.x) / (next.x - p.x);
|
|
1711
|
+
yVal = p.y + t * (next.y - p.y);
|
|
1712
|
+
if (t < 0.5 && p.style) pointStyle = p.style;
|
|
1713
|
+
else if (t >= 0.5 && next.style) pointStyle = next.style;
|
|
1714
|
+
break;
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
if (yVal !== null) {
|
|
1718
|
+
const row = Math.round((1 - (yVal - yMin) / yRange) * (plotHeight - 1));
|
|
1719
|
+
const clampedRow = Math.max(0, Math.min(plotHeight - 1, row));
|
|
1720
|
+
const char = defaultChar;
|
|
1721
|
+
grid[clampedRow][col] = pointStyle ? pointStyle(char) : char;
|
|
1722
|
+
if (fill) {
|
|
1723
|
+
for (let r = clampedRow + 1; r < plotHeight; r++) {
|
|
1724
|
+
if (grid[r][col] === " ") grid[r][col] = "\u2591";
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
if (showAxes) {
|
|
1730
|
+
const midRow = Math.floor((plotHeight - 1) / 2);
|
|
1731
|
+
for (let r = 0; r < plotHeight; r++) {
|
|
1732
|
+
let yLabel = "";
|
|
1733
|
+
if (r === 0) yLabel = formatNum(yMax);
|
|
1734
|
+
else if (r === midRow) yLabel = formatNum((yMin + yMax) / 2);
|
|
1735
|
+
else if (r === plotHeight - 1) yLabel = formatNum(yMin);
|
|
1736
|
+
const coloredLabel = yLabel ? applyConfigColor(yLabel) : "";
|
|
1737
|
+
this.string += padLeft(coloredLabel, yAxisWidth) + "\u2502" + grid[r].join("") + "\n";
|
|
1738
|
+
}
|
|
1739
|
+
this.string += " ".repeat(yAxisWidth) + "\u2514" + "\u2500".repeat(plotWidth) + "\n";
|
|
1740
|
+
const xMinRaw = formatNum(xMin);
|
|
1741
|
+
const xMidRaw = formatNum((xMin + xMax) / 2);
|
|
1742
|
+
const xMaxRaw = formatNum(xMax);
|
|
1743
|
+
const midCol = Math.floor(plotWidth / 2) - Math.floor(xMidRaw.length / 2);
|
|
1744
|
+
const gap1 = Math.max(0, midCol - xMinRaw.length);
|
|
1745
|
+
const gap2 = Math.max(0, plotWidth - xMinRaw.length - gap1 - xMidRaw.length - xMaxRaw.length);
|
|
1746
|
+
this.string += " ".repeat(yAxisWidth + 1) + applyConfigColor(xMinRaw) + " ".repeat(gap1) + applyConfigColor(xMidRaw) + " ".repeat(gap2) + applyConfigColor(xMaxRaw) + "\n";
|
|
1747
|
+
} else {
|
|
1748
|
+
for (const row of grid) {
|
|
1749
|
+
this.string += row.join("") + "\n";
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
|
|
1753
|
+
}
|
|
1754
|
+
print() {
|
|
1755
|
+
process.stdout.write(this.string);
|
|
1756
|
+
}
|
|
1757
|
+
toString() {
|
|
1758
|
+
return this.string;
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
function Sparkline(data, options = {}) {
|
|
1762
|
+
const lo = options.min ?? Math.min(...data);
|
|
1763
|
+
const hi = options.max ?? Math.max(...data);
|
|
1764
|
+
const range = hi === lo ? 1 : hi - lo;
|
|
1765
|
+
const chars = data.map((v) => {
|
|
1766
|
+
const idx = Math.min(8, Math.round(Math.max(0, Math.min(1, (v - lo) / range)) * 8));
|
|
1767
|
+
return BLOCKS[idx] ?? "\u2588";
|
|
1768
|
+
}).join("");
|
|
1769
|
+
return options.style ? options.style(chars) : chars;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// src/models/Column.ts
|
|
1773
|
+
var Column = class {
|
|
1774
|
+
constructor(data) {
|
|
1775
|
+
if (typeof data === "string") data = { key: data };
|
|
1776
|
+
this.key = data.key ?? "";
|
|
1777
|
+
this.title = data.title ?? this.key;
|
|
1778
|
+
this.padding = data.padding ?? 0;
|
|
1779
|
+
this.align = data.align;
|
|
1780
|
+
this.hidden = data.hidden;
|
|
1781
|
+
if (stringLength(this.title) > this.padding) this.padding = stringLength(this.title);
|
|
1782
|
+
if (data.minimumPadding && data.minimumPadding > this.padding) this.padding = data.minimumPadding;
|
|
1783
|
+
this.value = data.value ?? ((v) => v == null ? "" : String(v));
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1787
|
+
// src/models/Markup.ts
|
|
1788
|
+
var TAB = " ";
|
|
1789
|
+
function markup(data, options = {}) {
|
|
1790
|
+
const translations = options.translations ?? {};
|
|
1791
|
+
const styles = {
|
|
1792
|
+
date: options.styles?.date ?? ((v) => colorText(MAGENTA, v)),
|
|
1793
|
+
null: options.styles?.null ?? ((v) => colorText(BOLD, v)),
|
|
1794
|
+
undefined: options.styles?.undefined ?? ((v) => colorText(FAINT, v)),
|
|
1795
|
+
number: options.styles?.number ?? ((v) => colorText(YELLOW, v)),
|
|
1796
|
+
bigint: options.styles?.bigint ?? ((v) => colorText(YELLOW, v)),
|
|
1797
|
+
boolean: options.styles?.boolean ?? ((v) => colorText(CYAN, v)),
|
|
1798
|
+
string: options.styles?.string ?? ((v) => colorText(GREEN, v)),
|
|
1799
|
+
symbol: options.styles?.symbol ?? ((v) => colorText(BLUE, v))
|
|
1800
|
+
};
|
|
1801
|
+
let result = "";
|
|
1802
|
+
function formatPrimitive(value) {
|
|
1803
|
+
if (value instanceof Date) return styles.date(String(value));
|
|
1804
|
+
if (value === null) return styles.null("null");
|
|
1805
|
+
if (value === void 0) return styles.undefined("undefined");
|
|
1806
|
+
if (typeof value === "number") return styles.number(String(value));
|
|
1807
|
+
if (typeof value === "bigint") return styles.bigint(String(value));
|
|
1808
|
+
if (typeof value === "boolean") return styles.boolean(String(value));
|
|
1809
|
+
if (typeof value === "string") return styles.string(value);
|
|
1810
|
+
if (typeof value === "symbol") return styles.symbol(String(value));
|
|
1811
|
+
return String(value);
|
|
1812
|
+
}
|
|
1813
|
+
function isPrimitive(value) {
|
|
1814
|
+
return !Array.isArray(value) && (value === null || value === void 0 || typeof value !== "object" || value instanceof Date);
|
|
1815
|
+
}
|
|
1816
|
+
function isPlainObject(value) {
|
|
1817
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
1818
|
+
}
|
|
1819
|
+
function formatObjectContents(obj, pad) {
|
|
1820
|
+
const keys = Object.keys(obj);
|
|
1821
|
+
for (const [i, key] of keys.entries()) {
|
|
1822
|
+
result += `${pad}${TAB}${key}: `;
|
|
1823
|
+
let val = obj[key];
|
|
1824
|
+
if (translations[key]) val = translations[key](val);
|
|
1825
|
+
if (typeof val === "object" && val !== null) {
|
|
1826
|
+
format(val, `${pad}${TAB}`);
|
|
1827
|
+
} else {
|
|
1828
|
+
format(val, "");
|
|
1829
|
+
}
|
|
1830
|
+
result += i === keys.length - 1 ? "\n" : ",\n";
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
function format(value, pad) {
|
|
1834
|
+
if (Array.isArray(value)) {
|
|
1835
|
+
if (value.length === 0) {
|
|
1836
|
+
result += result.endsWith(": ") ? "[]" : `${pad}[]`;
|
|
1837
|
+
} else if (value.every(isPrimitive)) {
|
|
1838
|
+
const inline = `[${value.map(formatPrimitive).join(", ")}]`;
|
|
1839
|
+
result += result.endsWith(": ") ? inline : `${pad}${inline}`;
|
|
1840
|
+
} else if (value.every(isPlainObject)) {
|
|
1841
|
+
const prefix = result.endsWith(": ") ? "" : pad;
|
|
1842
|
+
for (const [i, item] of value.entries()) {
|
|
1843
|
+
result += i === 0 ? `${prefix}[{
|
|
1844
|
+
` : `${pad}},{
|
|
1845
|
+
`;
|
|
1846
|
+
formatObjectContents(item, pad);
|
|
1847
|
+
}
|
|
1848
|
+
result += `${pad}}]`;
|
|
1849
|
+
} else {
|
|
1850
|
+
result += result.endsWith(": ") ? "[" : `${pad}[`;
|
|
1851
|
+
result += "\n";
|
|
1852
|
+
for (const [i, item] of value.entries()) {
|
|
1853
|
+
format(item, `${pad}${TAB}`);
|
|
1854
|
+
result += i === value.length - 1 ? "\n" : ",\n";
|
|
1855
|
+
}
|
|
1856
|
+
result += `${pad}]`;
|
|
1857
|
+
}
|
|
1858
|
+
} else if (value instanceof Date) {
|
|
1859
|
+
result += styles.date(String(value));
|
|
1860
|
+
} else if (value === null) {
|
|
1861
|
+
result += styles.null("null");
|
|
1862
|
+
} else if (value === void 0) {
|
|
1863
|
+
result += styles.undefined("undefined");
|
|
1864
|
+
} else if (isPlainObject(value)) {
|
|
1865
|
+
result += result.endsWith(": ") ? "{" : `${pad}{`;
|
|
1866
|
+
const keys = Object.keys(value);
|
|
1867
|
+
if (keys.length === 0) {
|
|
1868
|
+
result += "}";
|
|
1869
|
+
} else {
|
|
1870
|
+
result += "\n";
|
|
1871
|
+
formatObjectContents(value, pad);
|
|
1872
|
+
result += `${pad}}`;
|
|
1873
|
+
}
|
|
1874
|
+
} else if (typeof value === "number") {
|
|
1875
|
+
result += styles.number(`${pad}${value}`);
|
|
1876
|
+
} else if (typeof value === "bigint") {
|
|
1877
|
+
result += styles.bigint(`${pad}${value}`);
|
|
1878
|
+
} else if (typeof value === "boolean") {
|
|
1879
|
+
result += styles.boolean(String(value));
|
|
1880
|
+
} else if (typeof value === "string") {
|
|
1881
|
+
result += styles.string(`${pad}${value}`);
|
|
1882
|
+
} else if (typeof value === "symbol") {
|
|
1883
|
+
result += styles.symbol(String(value));
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
format(data, "");
|
|
1887
|
+
return result;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// src/models/Log.ts
|
|
1891
|
+
var Log = class {
|
|
1892
|
+
constructor(options = {}) {
|
|
1893
|
+
this._successColor = options.successColor ?? GREEN;
|
|
1894
|
+
this._failColor = options.failColor ?? RED;
|
|
1895
|
+
this._warnColor = options.warnColor ?? YELLOW;
|
|
1896
|
+
this._infoColor = options.infoColor ?? BLUE;
|
|
1897
|
+
this._glyphs = options.glyphs ?? true;
|
|
1898
|
+
}
|
|
1899
|
+
write(glyph, color, message) {
|
|
1900
|
+
if (process.stdout.isTTY) {
|
|
1901
|
+
process.stdout.write(`${colorText(color, glyph)}${message ? ` ${message}` : ""}
|
|
1902
|
+
`);
|
|
1903
|
+
} else {
|
|
1904
|
+
process.stdout.write(`${this._glyphs ? `${glyph}${message ? ` ${message}` : ""}` : message ?? ""}
|
|
1905
|
+
`);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
succeed(message) {
|
|
1909
|
+
this.write("\u2714", this._successColor, message);
|
|
1910
|
+
}
|
|
1911
|
+
fail(message) {
|
|
1912
|
+
this.write("\u2716", this._failColor, message);
|
|
1913
|
+
}
|
|
1914
|
+
warn(message) {
|
|
1915
|
+
this.write("\u26A0", this._warnColor, message);
|
|
1916
|
+
}
|
|
1917
|
+
info(message) {
|
|
1918
|
+
this.write("\u2139", this._infoColor, message);
|
|
1919
|
+
}
|
|
1920
|
+
data(value, options) {
|
|
1921
|
+
process.stdout.write(`${markup(value, options)}
|
|
1922
|
+
`);
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
var log = new Log();
|
|
1926
|
+
|
|
1927
|
+
// src/models/MultiBar.ts
|
|
1928
|
+
var CURSOR_UP2 = (n) => `\x1B[${n}A`;
|
|
1929
|
+
var MultiBar = class {
|
|
1930
|
+
constructor(options = {}) {
|
|
1931
|
+
this._bars = [];
|
|
1932
|
+
this._running = false;
|
|
1933
|
+
this._linesWritten = 0;
|
|
1934
|
+
this._cleanupDeregister = null;
|
|
1935
|
+
this._interval = options.interval ?? 35;
|
|
1936
|
+
}
|
|
1937
|
+
// Add a bar to the group. Must be called before start().
|
|
1938
|
+
// Returns the Bar instance — use .message(), .progress, .tick(), .succeed(), etc.
|
|
1939
|
+
add(options = {}) {
|
|
1940
|
+
const bar = new Bar(options);
|
|
1941
|
+
bar._isManaged = true;
|
|
1942
|
+
this._bars.push(bar);
|
|
1943
|
+
return bar;
|
|
1944
|
+
}
|
|
1945
|
+
start() {
|
|
1946
|
+
if (!process.stdout.isTTY) return;
|
|
1947
|
+
this._running = true;
|
|
1948
|
+
this._linesWritten = 0;
|
|
1949
|
+
process.stdout.write(HIDE_CURSOR);
|
|
1950
|
+
this._cleanupDeregister = registerCleanup(() => {
|
|
1951
|
+
this._running = false;
|
|
1952
|
+
if (this._linesWritten > 0) process.stdout.write(CURSOR_UP2(this._linesWritten));
|
|
1953
|
+
process.stdout.write("\x1B[0J");
|
|
1954
|
+
process.stdout.write(SHOW_CURSOR);
|
|
1955
|
+
});
|
|
1956
|
+
this.render();
|
|
1957
|
+
}
|
|
1958
|
+
stop() {
|
|
1959
|
+
this._running = false;
|
|
1960
|
+
this._cleanupDeregister?.();
|
|
1961
|
+
this._cleanupDeregister = null;
|
|
1962
|
+
if (process.stdout.isTTY) process.stdout.write(SHOW_CURSOR);
|
|
1963
|
+
}
|
|
1964
|
+
render() {
|
|
1965
|
+
const width = Math.max(20, (process.stdout.columns ?? 80) - 1);
|
|
1966
|
+
if (this._linesWritten > 0) {
|
|
1967
|
+
process.stdout.write(CURSOR_UP2(this._linesWritten));
|
|
1968
|
+
}
|
|
1969
|
+
for (const bar of this._bars) {
|
|
1970
|
+
if (bar._managedFinalLine !== null) {
|
|
1971
|
+
process.stdout.write(`\r${bar._managedFinalLine}\x1B[K
|
|
1972
|
+
`);
|
|
1973
|
+
} else {
|
|
1974
|
+
process.stdout.write(`\r${bar.renderLine(width)}\x1B[K
|
|
1975
|
+
`);
|
|
1976
|
+
bar.advanceFrame();
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
this._linesWritten = this._bars.length;
|
|
1980
|
+
if (!this._running) return;
|
|
1981
|
+
if (this._bars.every((b) => b._managedFinalLine !== null)) {
|
|
1982
|
+
this._running = false;
|
|
1983
|
+
this._cleanupDeregister?.();
|
|
1984
|
+
this._cleanupDeregister = null;
|
|
1985
|
+
process.stdout.write(SHOW_CURSOR);
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
setTimeout(() => {
|
|
1989
|
+
if (this._running) this.render();
|
|
1990
|
+
}, this._interval);
|
|
1991
|
+
}
|
|
1992
|
+
};
|
|
1993
|
+
|
|
1994
|
+
// src/models/MultiSelect.ts
|
|
1995
|
+
var CLEAR_LINE2 = "\x1B[2K";
|
|
1996
|
+
var CURSOR_UP3 = (n) => `\x1B[${n}A`;
|
|
1997
|
+
var DIM2 = "\x1B[2m";
|
|
1998
|
+
var MultiSelect = class {
|
|
1999
|
+
constructor(options = {}) {
|
|
2000
|
+
this._colorOffset = 0;
|
|
2001
|
+
this._shimmerPhase = 0;
|
|
2002
|
+
this.promptColor = options.promptColor ?? resolveColor(config.color);
|
|
2003
|
+
this.promptGlyph = options.promptGlyph ?? (config.glyphs ? "\u25C6" : ">");
|
|
2004
|
+
this.descriptionColor = options.descriptionColor ?? BLUE;
|
|
2005
|
+
this.errorColor = options.errorColor ?? RED;
|
|
2006
|
+
this.checkedPrefix = options.checkedPrefix ?? (config.glyphs ? "\u25C9" : "[x]");
|
|
2007
|
+
this.uncheckedPrefix = options.uncheckedPrefix ?? (config.glyphs ? "\u25CB" : "[ ]");
|
|
2008
|
+
this.colorCycle = options.colorCycle ?? 1;
|
|
2009
|
+
this.shimmer = options.shimmer ?? 0;
|
|
2010
|
+
this.interval = options.interval ?? 80;
|
|
2011
|
+
this.min = options.min ?? 0;
|
|
2012
|
+
this.max = options.max ?? null;
|
|
2013
|
+
this.allowSkip = options.allowSkip ?? false;
|
|
2014
|
+
this.searchEnabled = options.search ?? false;
|
|
2015
|
+
this.maxHeight = options.maxHeight;
|
|
2016
|
+
const colors = options.colors ?? config.pulseColors;
|
|
2017
|
+
this._parsedColors = colors.length >= 2 ? colors.map(parseHex) : [];
|
|
2018
|
+
}
|
|
2019
|
+
pulseColor() {
|
|
2020
|
+
if (this._parsedColors.length < 2) return "";
|
|
2021
|
+
const t = (this._colorOffset % 1 + 1) % 1;
|
|
2022
|
+
const base2 = interpolateColor(this._parsedColors, t);
|
|
2023
|
+
const color = applyShimmer(base2, 0.5, this._shimmerPhase, this.shimmer);
|
|
2024
|
+
return formatColor(38, color);
|
|
2025
|
+
}
|
|
2026
|
+
async ask(prompt, items) {
|
|
2027
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("MultiSelect requires an interactive terminal");
|
|
2028
|
+
let cursor = 0;
|
|
2029
|
+
let viewportOffset = 0;
|
|
2030
|
+
let searchQuery = "";
|
|
2031
|
+
const checked = /* @__PURE__ */ new Set();
|
|
2032
|
+
let error = null;
|
|
2033
|
+
let lastDrawnLines = 0;
|
|
2034
|
+
process.stdout.write(HIDE_CURSOR);
|
|
2035
|
+
const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
|
|
2036
|
+
const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
|
|
2037
|
+
process.stdout.write(`${glyph}${prompt}
|
|
2038
|
+
`);
|
|
2039
|
+
const getFiltered = () => {
|
|
2040
|
+
if (!this.searchEnabled || searchQuery === "") return items.map((item, i) => ({ item, originalIndex: i }));
|
|
2041
|
+
const q = searchQuery.toLowerCase();
|
|
2042
|
+
return items.map((item, i) => ({ item, originalIndex: i })).filter(({ item }) => item.label.toLowerCase().includes(q) || (item.description?.toLowerCase().includes(q) ?? false));
|
|
2043
|
+
};
|
|
2044
|
+
const renderList = (redraw) => {
|
|
2045
|
+
const filtered = getFiltered();
|
|
2046
|
+
if (cursor >= filtered.length) cursor = Math.max(0, filtered.length - 1);
|
|
2047
|
+
if (this.maxHeight) {
|
|
2048
|
+
if (cursor < viewportOffset) viewportOffset = cursor;
|
|
2049
|
+
else if (cursor >= viewportOffset + this.maxHeight) viewportOffset = cursor - this.maxHeight + 1;
|
|
2050
|
+
viewportOffset = Math.max(0, Math.min(viewportOffset, Math.max(0, filtered.length - this.maxHeight)));
|
|
2051
|
+
}
|
|
2052
|
+
const visibleStart = this.maxHeight ? viewportOffset : 0;
|
|
2053
|
+
const visibleEnd = this.maxHeight ? Math.min(filtered.length, viewportOffset + this.maxHeight) : filtered.length;
|
|
2054
|
+
if (redraw) {
|
|
2055
|
+
if (lastDrawnLines > 0) process.stdout.write(CURSOR_UP3(lastDrawnLines));
|
|
2056
|
+
process.stdout.write("\r\x1B[0J");
|
|
2057
|
+
}
|
|
2058
|
+
lastDrawnLines = 0;
|
|
2059
|
+
if (this.searchEnabled) {
|
|
2060
|
+
process.stdout.write(`\r${indent}${colorText(this.promptColor, "/")} ${searchQuery}|
|
|
2061
|
+
`);
|
|
2062
|
+
lastDrawnLines++;
|
|
2063
|
+
}
|
|
2064
|
+
const pulse = this.pulseColor();
|
|
2065
|
+
for (let vi = visibleStart; vi < visibleEnd; vi++) {
|
|
2066
|
+
const { item, originalIndex } = filtered[vi];
|
|
2067
|
+
const isCursor = vi === cursor;
|
|
2068
|
+
const isChecked = checked.has(originalIndex);
|
|
2069
|
+
const desc = item.description ? ` ${colorText(this.descriptionColor, `\u2014 ${item.description}`)}` : "";
|
|
2070
|
+
const checkMark = isChecked ? pulse ? `${pulse}${this.checkedPrefix}${RESET}` : colorText(this.promptColor, this.checkedPrefix) : this.uncheckedPrefix;
|
|
2071
|
+
const label = isCursor ? pulse ? `${pulse}${item.label}${RESET}` : colorText(this.promptColor, item.label) : item.label;
|
|
2072
|
+
process.stdout.write(`\r${indent}${checkMark} ${label}${desc}
|
|
2073
|
+
`);
|
|
2074
|
+
lastDrawnLines++;
|
|
2075
|
+
}
|
|
2076
|
+
const hintContent = `\u2191\u2193 move space/tab toggle \u2190\u2192 deselect/select${this.searchEnabled ? " type to filter" : " a all"} enter confirm`;
|
|
2077
|
+
const maxHintCols = Math.max(10, (process.stdout.columns ?? 80) - stringLength(indent) - 1);
|
|
2078
|
+
const hint = stringLength(hintContent) > maxHintCols ? hintContent.slice(0, maxHintCols) : hintContent;
|
|
2079
|
+
process.stdout.write(`\r${indent}${DIM2}${hint}${RESET}
|
|
2080
|
+
`);
|
|
2081
|
+
lastDrawnLines++;
|
|
2082
|
+
if (error) {
|
|
2083
|
+
process.stdout.write(`\r${indent}${colorText(this.errorColor, `\u2717 ${error}`)}
|
|
2084
|
+
`);
|
|
2085
|
+
lastDrawnLines++;
|
|
2086
|
+
}
|
|
2087
|
+
};
|
|
2088
|
+
renderList(false);
|
|
2089
|
+
return new Promise((resolve) => {
|
|
2090
|
+
let timer = null;
|
|
2091
|
+
const deregisterCleanup = registerCleanup(() => {
|
|
2092
|
+
if (timer) {
|
|
2093
|
+
clearInterval(timer);
|
|
2094
|
+
timer = null;
|
|
2095
|
+
}
|
|
2096
|
+
process.stdin.setRawMode(false);
|
|
2097
|
+
process.stdin.pause();
|
|
2098
|
+
process.stdin.removeListener("data", onKey);
|
|
2099
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2100
|
+
});
|
|
2101
|
+
const cleanup = (result) => {
|
|
2102
|
+
deregisterCleanup();
|
|
2103
|
+
if (timer) {
|
|
2104
|
+
clearInterval(timer);
|
|
2105
|
+
timer = null;
|
|
2106
|
+
}
|
|
2107
|
+
if (lastDrawnLines > 0) process.stdout.write(CURSOR_UP3(lastDrawnLines));
|
|
2108
|
+
process.stdout.write("\x1B[0J");
|
|
2109
|
+
const bulletWidth = stringLength(this.checkedPrefix) + 1;
|
|
2110
|
+
for (let i = 0; i < items.length; i++) {
|
|
2111
|
+
const item = items[i];
|
|
2112
|
+
const bullet = checked.has(i) ? `${colorText(this.promptColor, this.checkedPrefix)} ` : " ".repeat(bulletWidth);
|
|
2113
|
+
process.stdout.write(`\r${indent}${bullet}${item.label}
|
|
2114
|
+
`);
|
|
2115
|
+
}
|
|
2116
|
+
process.stdout.write(`\r${CLEAR_LINE2}`);
|
|
2117
|
+
process.stdin.setRawMode(false);
|
|
2118
|
+
process.stdin.pause();
|
|
2119
|
+
process.stdin.removeListener("data", onKey);
|
|
2120
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2121
|
+
resolve(result);
|
|
2122
|
+
};
|
|
2123
|
+
if (this._parsedColors.length >= 2) {
|
|
2124
|
+
timer = setInterval(() => {
|
|
2125
|
+
this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
|
|
2126
|
+
if (this.shimmer > 0) this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
|
|
2127
|
+
renderList(true);
|
|
2128
|
+
}, this.interval);
|
|
2129
|
+
}
|
|
2130
|
+
const onKey = (key) => {
|
|
2131
|
+
const str = key.toString();
|
|
2132
|
+
const filtered = getFiltered();
|
|
2133
|
+
const safeLen = Math.max(1, filtered.length);
|
|
2134
|
+
if (str === "\x1B[A" || str === "\x1B[Z") {
|
|
2135
|
+
error = null;
|
|
2136
|
+
cursor = (cursor - 1 + safeLen) % safeLen;
|
|
2137
|
+
renderList(true);
|
|
2138
|
+
} else if (str === "\x1B[B") {
|
|
2139
|
+
error = null;
|
|
2140
|
+
cursor = (cursor + 1) % safeLen;
|
|
2141
|
+
renderList(true);
|
|
2142
|
+
} else if (str === " " || str === " ") {
|
|
2143
|
+
const entry = filtered[cursor];
|
|
2144
|
+
if (!entry) return;
|
|
2145
|
+
const oi = entry.originalIndex;
|
|
2146
|
+
if (checked.has(oi)) {
|
|
2147
|
+
error = null;
|
|
2148
|
+
checked.delete(oi);
|
|
2149
|
+
} else if (this.max === null || checked.size < this.max) {
|
|
2150
|
+
error = null;
|
|
2151
|
+
checked.add(oi);
|
|
2152
|
+
} else {
|
|
2153
|
+
error = `Maximum ${this.max} item${this.max !== 1 ? "s" : ""} allowed`;
|
|
2154
|
+
}
|
|
2155
|
+
renderList(true);
|
|
2156
|
+
} else if (str === "\x1B[C") {
|
|
2157
|
+
const entry = filtered[cursor];
|
|
2158
|
+
if (!entry) return;
|
|
2159
|
+
const oi = entry.originalIndex;
|
|
2160
|
+
if (!checked.has(oi)) {
|
|
2161
|
+
if (this.max === null || checked.size < this.max) {
|
|
2162
|
+
error = null;
|
|
2163
|
+
checked.add(oi);
|
|
2164
|
+
} else {
|
|
2165
|
+
error = `Maximum ${this.max} item${this.max !== 1 ? "s" : ""} allowed`;
|
|
2166
|
+
}
|
|
2167
|
+
renderList(true);
|
|
2168
|
+
}
|
|
2169
|
+
} else if (str === "\x1B[D") {
|
|
2170
|
+
const entry = filtered[cursor];
|
|
2171
|
+
if (!entry) return;
|
|
2172
|
+
const oi = entry.originalIndex;
|
|
2173
|
+
if (checked.has(oi)) {
|
|
2174
|
+
error = null;
|
|
2175
|
+
checked.delete(oi);
|
|
2176
|
+
renderList(true);
|
|
2177
|
+
}
|
|
2178
|
+
} else if (str === "a" && !this.searchEnabled) {
|
|
2179
|
+
if (checked.size === items.length) {
|
|
2180
|
+
checked.clear();
|
|
2181
|
+
error = null;
|
|
2182
|
+
} else if (this.max !== null && items.length > this.max) {
|
|
2183
|
+
error = `Maximum ${this.max} item${this.max !== 1 ? "s" : ""} allowed`;
|
|
2184
|
+
} else {
|
|
2185
|
+
for (let i = 0; i < items.length; i++) checked.add(i);
|
|
2186
|
+
error = null;
|
|
2187
|
+
}
|
|
2188
|
+
renderList(true);
|
|
2189
|
+
} else if (str === "\r" || str === "\n") {
|
|
2190
|
+
const entry = filtered[cursor];
|
|
2191
|
+
if (checked.size === 0 && entry) checked.add(entry.originalIndex);
|
|
2192
|
+
if (checked.size < this.min) {
|
|
2193
|
+
error = `Select at least ${this.min} item${this.min !== 1 ? "s" : ""}`;
|
|
2194
|
+
renderList(true);
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
cleanup(items.filter((_, i) => checked.has(i)));
|
|
2198
|
+
} else if (str === "\x1B") {
|
|
2199
|
+
if (this.allowSkip) cleanup(null);
|
|
2200
|
+
} else if (str === "") {
|
|
2201
|
+
deregisterCleanup();
|
|
2202
|
+
if (timer) {
|
|
2203
|
+
clearInterval(timer);
|
|
2204
|
+
timer = null;
|
|
2205
|
+
}
|
|
2206
|
+
process.stdin.setRawMode(false);
|
|
2207
|
+
process.stdin.pause();
|
|
2208
|
+
process.stdin.removeListener("data", onKey);
|
|
2209
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2210
|
+
process.exit(130);
|
|
2211
|
+
} else if (this.searchEnabled) {
|
|
2212
|
+
if (str === "\x7F" || str === "\b") {
|
|
2213
|
+
searchQuery = searchQuery.slice(0, -1);
|
|
2214
|
+
cursor = 0;
|
|
2215
|
+
viewportOffset = 0;
|
|
2216
|
+
error = null;
|
|
2217
|
+
renderList(true);
|
|
2218
|
+
} else if (str.length === 1 && str >= " ") {
|
|
2219
|
+
searchQuery += str;
|
|
2220
|
+
cursor = 0;
|
|
2221
|
+
viewportOffset = 0;
|
|
2222
|
+
error = null;
|
|
2223
|
+
renderList(true);
|
|
2224
|
+
}
|
|
2225
|
+
} else {
|
|
2226
|
+
const n = parseInt(str);
|
|
2227
|
+
if (!isNaN(n) && n >= 1 && n <= Math.min(filtered.length, 9)) {
|
|
2228
|
+
error = null;
|
|
2229
|
+
cursor = viewportOffset + n - 1;
|
|
2230
|
+
renderList(true);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
process.stdin.setRawMode(true);
|
|
2235
|
+
process.stdin.resume();
|
|
2236
|
+
process.stdin.on("data", onKey);
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
};
|
|
2240
|
+
async function multiSelect(prompt, items, options) {
|
|
2241
|
+
return new MultiSelect(options).ask(prompt, items);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// src/utils/truncate.ts
|
|
2245
|
+
var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
|
|
2246
|
+
var RESET2 = "\x1B[0m";
|
|
2247
|
+
function truncate(str, maxLength, suffix = "\u2026") {
|
|
2248
|
+
if (stringLength(str) <= maxLength) return str;
|
|
2249
|
+
const hasAnsi = ANSI_RE.test(str);
|
|
2250
|
+
ANSI_RE.lastIndex = 0;
|
|
2251
|
+
const suffixLen = stringLength(suffix);
|
|
2252
|
+
const target = Math.max(0, maxLength - suffixLen);
|
|
2253
|
+
let visible = 0;
|
|
2254
|
+
let i = 0;
|
|
2255
|
+
while (i < str.length && visible < target) {
|
|
2256
|
+
if (str[i] === "\x1B") {
|
|
2257
|
+
const m = str.slice(i).match(ANSI_RE);
|
|
2258
|
+
if (m) {
|
|
2259
|
+
i += m[0].length;
|
|
2260
|
+
continue;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
visible++;
|
|
2264
|
+
i++;
|
|
2265
|
+
}
|
|
2266
|
+
return str.slice(0, i) + (hasAnsi ? RESET2 : "") + suffix;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
// src/utils/wrap.ts
|
|
2270
|
+
function wrap(str, width) {
|
|
2271
|
+
const words = str.split(" ");
|
|
2272
|
+
const lines = [];
|
|
2273
|
+
let current = "";
|
|
2274
|
+
let currentLen = 0;
|
|
2275
|
+
for (const word of words) {
|
|
2276
|
+
const wordLen = stringLength(word);
|
|
2277
|
+
if (currentLen === 0) {
|
|
2278
|
+
current = word;
|
|
2279
|
+
currentLen = wordLen;
|
|
2280
|
+
} else if (currentLen + 1 + wordLen <= width) {
|
|
2281
|
+
current += " " + word;
|
|
2282
|
+
currentLen += 1 + wordLen;
|
|
2283
|
+
} else {
|
|
2284
|
+
lines.push(current);
|
|
2285
|
+
current = word;
|
|
2286
|
+
currentLen = wordLen;
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
if (current) lines.push(current);
|
|
2290
|
+
return lines.join("\n");
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
// src/models/Scrollbox.ts
|
|
2294
|
+
var CURSOR_UP4 = (n) => `\x1B[${n}A`;
|
|
2295
|
+
var DIM3 = "\x1B[2m";
|
|
2296
|
+
var Scrollbox = class {
|
|
2297
|
+
constructor(options = {}) {
|
|
2298
|
+
this.height = options.height ?? 10;
|
|
2299
|
+
this.title = options.title;
|
|
2300
|
+
this.lineNumbers = options.lineNumbers ?? false;
|
|
2301
|
+
this.showScrollbar = options.scrollbar ?? true;
|
|
2302
|
+
this.borderColor = options.borderColor ?? DIM3;
|
|
2303
|
+
this.wrapLines = options.wrapLines ?? false;
|
|
2304
|
+
}
|
|
2305
|
+
async show(lines) {
|
|
2306
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Scrollbox requires an interactive terminal");
|
|
2307
|
+
const termWidth = process.stdout.columns ?? 80;
|
|
2308
|
+
const lineNumWidth = this.lineNumbers ? String(lines.length).length + 2 : 0;
|
|
2309
|
+
const gutterWidth = this.showScrollbar ? 1 : 0;
|
|
2310
|
+
const contentWidth = Math.max(10, termWidth - lineNumWidth - gutterWidth);
|
|
2311
|
+
const displayLines = this.wrapLines ? lines.flatMap((line) => wrap(line, contentWidth).split("\n")) : lines;
|
|
2312
|
+
const total = displayLines.length;
|
|
2313
|
+
let offset = 0;
|
|
2314
|
+
let lastDrawnLines = 0;
|
|
2315
|
+
process.stdout.write(HIDE_CURSOR);
|
|
2316
|
+
const render = (redraw) => {
|
|
2317
|
+
offset = Math.max(0, Math.min(offset, Math.max(0, total - this.height)));
|
|
2318
|
+
if (redraw && lastDrawnLines > 0) {
|
|
2319
|
+
process.stdout.write(CURSOR_UP4(lastDrawnLines));
|
|
2320
|
+
process.stdout.write("\x1B[0J");
|
|
2321
|
+
}
|
|
2322
|
+
lastDrawnLines = 0;
|
|
2323
|
+
if (this.title) {
|
|
2324
|
+
process.stdout.write(`\r${colorText(this.borderColor, this.title)}
|
|
2325
|
+
`);
|
|
2326
|
+
lastDrawnLines++;
|
|
2327
|
+
}
|
|
2328
|
+
let thumbStart = 0;
|
|
2329
|
+
let thumbEnd = this.height;
|
|
2330
|
+
if (this.showScrollbar && total > this.height) {
|
|
2331
|
+
const thumbSize = Math.max(1, Math.floor(this.height / total * this.height));
|
|
2332
|
+
thumbStart = Math.floor(offset / Math.max(1, total - this.height) * (this.height - thumbSize));
|
|
2333
|
+
thumbEnd = thumbStart + thumbSize;
|
|
2334
|
+
}
|
|
2335
|
+
const visibleEnd = Math.min(total, offset + this.height);
|
|
2336
|
+
for (let i = offset; i < visibleEnd; i++) {
|
|
2337
|
+
const relIdx = i - offset;
|
|
2338
|
+
const numStr = this.lineNumbers ? `${colorText(this.borderColor, String(i + 1).padStart(lineNumWidth - 1))} ` : "";
|
|
2339
|
+
const content = this.wrapLines ? displayLines[i] : truncate(displayLines[i], contentWidth);
|
|
2340
|
+
const paddedContent = padRight(content, contentWidth);
|
|
2341
|
+
const gutter = this.showScrollbar ? total > this.height && relIdx >= thumbStart && relIdx < thumbEnd ? "\u2588" : colorText(this.borderColor, "\u2595") : "";
|
|
2342
|
+
process.stdout.write(`\r${numStr}${paddedContent}${gutter}
|
|
2343
|
+
`);
|
|
2344
|
+
lastDrawnLines++;
|
|
2345
|
+
}
|
|
2346
|
+
const pct = total <= this.height ? "100%" : `${Math.round(offset / (total - this.height) * 100)}%`;
|
|
2347
|
+
process.stdout.write(`\r${DIM3}\u2191\u2193/jk line space/b page g/G top/end q close ${pct}${RESET}
|
|
2348
|
+
`);
|
|
2349
|
+
lastDrawnLines++;
|
|
2350
|
+
};
|
|
2351
|
+
render(false);
|
|
2352
|
+
return new Promise((resolve) => {
|
|
2353
|
+
const deregisterCleanup = registerCleanup(() => {
|
|
2354
|
+
process.stdin.setRawMode(false);
|
|
2355
|
+
process.stdin.pause();
|
|
2356
|
+
process.stdin.removeListener("data", onKey);
|
|
2357
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2358
|
+
});
|
|
2359
|
+
const cleanup = () => {
|
|
2360
|
+
deregisterCleanup();
|
|
2361
|
+
process.stdin.setRawMode(false);
|
|
2362
|
+
process.stdin.pause();
|
|
2363
|
+
process.stdin.removeListener("data", onKey);
|
|
2364
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2365
|
+
resolve();
|
|
2366
|
+
};
|
|
2367
|
+
const onKey = (key) => {
|
|
2368
|
+
const str = key.toString();
|
|
2369
|
+
if (str === "\x1B[A" || str === "k") {
|
|
2370
|
+
offset--;
|
|
2371
|
+
render(true);
|
|
2372
|
+
} else if (str === "\x1B[B" || str === "j") {
|
|
2373
|
+
offset++;
|
|
2374
|
+
render(true);
|
|
2375
|
+
} else if (str === " " || str === "\x1B[6~") {
|
|
2376
|
+
offset += this.height;
|
|
2377
|
+
render(true);
|
|
2378
|
+
} else if (str === "b" || str === "\x1B[5~") {
|
|
2379
|
+
offset -= this.height;
|
|
2380
|
+
render(true);
|
|
2381
|
+
} else if (str === "g") {
|
|
2382
|
+
offset = 0;
|
|
2383
|
+
render(true);
|
|
2384
|
+
} else if (str === "G") {
|
|
2385
|
+
offset = total;
|
|
2386
|
+
render(true);
|
|
2387
|
+
} else if (str === "q" || str === "\x1B" || str === "\r" || str === "\n") {
|
|
2388
|
+
cleanup();
|
|
2389
|
+
} else if (str === "") {
|
|
2390
|
+
cleanup();
|
|
2391
|
+
process.exit(130);
|
|
2392
|
+
}
|
|
2393
|
+
};
|
|
2394
|
+
process.stdin.setRawMode(true);
|
|
2395
|
+
process.stdin.resume();
|
|
2396
|
+
process.stdin.on("data", onKey);
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2399
|
+
};
|
|
2400
|
+
async function scrollbox(lines, options) {
|
|
2401
|
+
return new Scrollbox(options).show(lines);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// src/models/Spinner.ts
|
|
2405
|
+
var _Spinner = class _Spinner {
|
|
2406
|
+
constructor(options = {}) {
|
|
2407
|
+
this._colors = [];
|
|
2408
|
+
this._parsedColors = [];
|
|
2409
|
+
this._bgColors = [];
|
|
2410
|
+
this._parsedBgColors = [];
|
|
2411
|
+
this._colorOffset = 0;
|
|
2412
|
+
this._shimmerPhase = 0;
|
|
2413
|
+
this._lastLineLength = 0;
|
|
2414
|
+
this._cleanupDeregister = null;
|
|
2415
|
+
this.running = false;
|
|
2416
|
+
this.frameIndex = 0;
|
|
2417
|
+
this.frames = options.frames ?? (config.glyphs ? _Spinner.FRAMES.braille : _Spinner.FRAMES.line);
|
|
2418
|
+
this.prefixString = options.prefix ?? "";
|
|
2419
|
+
this.suffixString = options.suffix ?? "";
|
|
2420
|
+
this.text = options.text ?? "";
|
|
2421
|
+
this.reverse = options.reverse ?? false;
|
|
2422
|
+
this.interval = options.interval ?? 80;
|
|
2423
|
+
this.colorCycle = options.colorCycle ?? 1;
|
|
2424
|
+
this.shimmer = options.shimmer ?? 0;
|
|
2425
|
+
this.onSpin = options.onSpin;
|
|
2426
|
+
this.colors = options.colors ?? ["#c026d3", "#e879f9"];
|
|
2427
|
+
this.bgColors = options.bgColors ?? [];
|
|
2428
|
+
this._successColor = options.successColor ?? GREEN;
|
|
2429
|
+
this._failColor = options.failColor ?? RED;
|
|
2430
|
+
this._warnColor = options.warnColor ?? YELLOW;
|
|
2431
|
+
this._infoColor = options.infoColor ?? BLUE;
|
|
2432
|
+
this._glyphs = options.glyphs ?? config.glyphs;
|
|
2433
|
+
}
|
|
2434
|
+
get colors() {
|
|
2435
|
+
return this._colors;
|
|
2436
|
+
}
|
|
2437
|
+
set colors(value) {
|
|
2438
|
+
this._colors = value;
|
|
2439
|
+
this._parsedColors = value.length > 1 ? value.map(parseHex) : [];
|
|
2440
|
+
}
|
|
2441
|
+
get bgColors() {
|
|
2442
|
+
return this._bgColors;
|
|
2443
|
+
}
|
|
2444
|
+
set bgColors(value) {
|
|
2445
|
+
this._bgColors = value;
|
|
2446
|
+
this._parsedBgColors = value.length > 1 ? value.map(parseHex) : [];
|
|
2447
|
+
}
|
|
2448
|
+
start() {
|
|
2449
|
+
if (!process.stdout.isTTY) return;
|
|
2450
|
+
this.running = true;
|
|
2451
|
+
process.stdout.write(HIDE_CURSOR);
|
|
2452
|
+
this._cleanupDeregister = registerCleanup(() => {
|
|
2453
|
+
this.running = false;
|
|
2454
|
+
process.stdout.clearLine?.(0);
|
|
2455
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2456
|
+
});
|
|
2457
|
+
this.run();
|
|
2458
|
+
}
|
|
2459
|
+
stop(message) {
|
|
2460
|
+
this.running = false;
|
|
2461
|
+
this._cleanupDeregister?.();
|
|
2462
|
+
this._cleanupDeregister = null;
|
|
2463
|
+
if (process.stdout.isTTY) {
|
|
2464
|
+
this.clear();
|
|
2465
|
+
process.stdout.write(SHOW_CURSOR);
|
|
2466
|
+
}
|
|
2467
|
+
if (message) process.stdout.write(`${message}
|
|
2468
|
+
`);
|
|
2469
|
+
return this;
|
|
2470
|
+
}
|
|
2471
|
+
message(string) {
|
|
2472
|
+
this.text = string;
|
|
2473
|
+
return this;
|
|
2474
|
+
}
|
|
2475
|
+
succeed(string) {
|
|
2476
|
+
this.running = false;
|
|
2477
|
+
this._cleanupDeregister?.();
|
|
2478
|
+
this._cleanupDeregister = null;
|
|
2479
|
+
if (process.stdout.isTTY) {
|
|
2480
|
+
this.clear();
|
|
2481
|
+
const glyph = this._glyphs ? colorText(this._successColor, "\u2714") + " " : "";
|
|
2482
|
+
process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
|
|
2483
|
+
`);
|
|
2484
|
+
} else {
|
|
2485
|
+
process.stdout.write(`${this._glyphs ? `\u2714 ${string ?? ""}` : string ?? ""}
|
|
2486
|
+
`);
|
|
2487
|
+
}
|
|
2488
|
+
return this;
|
|
2489
|
+
}
|
|
2490
|
+
fail(string) {
|
|
2491
|
+
this.running = false;
|
|
2492
|
+
this._cleanupDeregister?.();
|
|
2493
|
+
this._cleanupDeregister = null;
|
|
2494
|
+
if (process.stdout.isTTY) {
|
|
2495
|
+
this.clear();
|
|
2496
|
+
const glyph = this._glyphs ? colorText(this._failColor, "\u2716") + " " : "";
|
|
2497
|
+
process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
|
|
2498
|
+
`);
|
|
2499
|
+
} else {
|
|
2500
|
+
process.stdout.write(`${this._glyphs ? `\u2716 ${string ?? ""}` : string ?? ""}
|
|
2501
|
+
`);
|
|
2502
|
+
}
|
|
2503
|
+
return this;
|
|
2504
|
+
}
|
|
2505
|
+
warn(string) {
|
|
2506
|
+
this.running = false;
|
|
2507
|
+
this._cleanupDeregister?.();
|
|
2508
|
+
this._cleanupDeregister = null;
|
|
2509
|
+
if (process.stdout.isTTY) {
|
|
2510
|
+
this.clear();
|
|
2511
|
+
const glyph = this._glyphs ? colorText(this._warnColor, "\u26A0") + " " : "";
|
|
2512
|
+
process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
|
|
2513
|
+
`);
|
|
2514
|
+
} else {
|
|
2515
|
+
process.stdout.write(`${this._glyphs ? `\u26A0 ${string ?? ""}` : string ?? ""}
|
|
2516
|
+
`);
|
|
2517
|
+
}
|
|
2518
|
+
return this;
|
|
2519
|
+
}
|
|
2520
|
+
info(string) {
|
|
2521
|
+
this.running = false;
|
|
2522
|
+
this._cleanupDeregister?.();
|
|
2523
|
+
this._cleanupDeregister = null;
|
|
2524
|
+
if (process.stdout.isTTY) {
|
|
2525
|
+
this.clear();
|
|
2526
|
+
const glyph = this._glyphs ? colorText(this._infoColor, "\u2139") + " " : "";
|
|
2527
|
+
process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
|
|
2528
|
+
`);
|
|
2529
|
+
} else {
|
|
2530
|
+
process.stdout.write(`${this._glyphs ? `\u2139 ${string ?? ""}` : string ?? ""}
|
|
2531
|
+
`);
|
|
2532
|
+
}
|
|
2533
|
+
return this;
|
|
2534
|
+
}
|
|
2535
|
+
clear() {
|
|
2536
|
+
process.stdout.clearLine?.(0);
|
|
2537
|
+
this._lastLineLength = 0;
|
|
2538
|
+
}
|
|
2539
|
+
coloredFrame() {
|
|
2540
|
+
const t = this._parsedColors.length >= 2 && this.frames.length > 1 ? this.frameIndex / (this.frames.length - 1) : 0;
|
|
2541
|
+
const et = this.colorCycle > 0 ? ((t + this._colorOffset) % 1 + 1) % 1 : t;
|
|
2542
|
+
const frame = this.frames[this.frameIndex];
|
|
2543
|
+
const fg = this._parsedColors.length >= 2 ? formatColor(38, applyShimmer(interpolateColor(this._parsedColors, et), 0.5, this._shimmerPhase, this.shimmer)) : "";
|
|
2544
|
+
const bg = this._parsedBgColors.length >= 2 ? formatColor(48, applyShimmer(interpolateColor(this._parsedBgColors, et), 0.5, this._shimmerPhase, this.shimmer)) : "";
|
|
2545
|
+
return fg || bg ? fg + bg + frame + RESET : frame;
|
|
2546
|
+
}
|
|
2547
|
+
run() {
|
|
2548
|
+
const frame = this.coloredFrame();
|
|
2549
|
+
const t = this.text;
|
|
2550
|
+
const content = this.reverse ? t ? `${t} ${frame}` : frame : t ? `${frame} ${t}` : frame;
|
|
2551
|
+
const raw = `${this.prefixString}${content}${this.suffixString}`;
|
|
2552
|
+
const displayLen = stringLength(raw);
|
|
2553
|
+
const padding = " ".repeat(Math.max(0, this._lastLineLength - displayLen));
|
|
2554
|
+
this._lastLineLength = displayLen;
|
|
2555
|
+
process.stdout.write(`${raw}${padding}\r`);
|
|
2556
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
2557
|
+
if (this.frameIndex === 0) this.onSpin?.();
|
|
2558
|
+
if (this.colorCycle > 0) {
|
|
2559
|
+
this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
|
|
2560
|
+
}
|
|
2561
|
+
if (this.shimmer > 0) {
|
|
2562
|
+
this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
|
|
2563
|
+
}
|
|
2564
|
+
setTimeout(() => {
|
|
2565
|
+
if (this.running) this.run();
|
|
2566
|
+
}, this.interval);
|
|
2567
|
+
}
|
|
2568
|
+
};
|
|
2569
|
+
_Spinner.FRAMES = {
|
|
2570
|
+
braille: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
|
|
2571
|
+
dots: ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"],
|
|
2572
|
+
line: ["|", "/", "-", "\\"],
|
|
2573
|
+
arrow: ["\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198", "\u2193", "\u2199"],
|
|
2574
|
+
bounce: ["\u2801", "\u2802", "\u2804", "\u2802"]
|
|
2575
|
+
};
|
|
2576
|
+
var Spinner = _Spinner;
|
|
2577
|
+
|
|
2578
|
+
// src/models/Table.ts
|
|
2579
|
+
import cosmetic2 from "cosmetic";
|
|
2580
|
+
|
|
2581
|
+
// src/utils/padSides.ts
|
|
2582
|
+
var padSides = (string, padding) => {
|
|
2583
|
+
let alt = false;
|
|
2584
|
+
while (stringLength(string) < padding) {
|
|
2585
|
+
if (alt) {
|
|
2586
|
+
string = ` ${string}`;
|
|
2587
|
+
} else {
|
|
2588
|
+
string += " ";
|
|
2589
|
+
}
|
|
2590
|
+
alt = !alt;
|
|
2591
|
+
}
|
|
2592
|
+
return string;
|
|
2593
|
+
};
|
|
2594
|
+
|
|
2595
|
+
// src/models/Table.ts
|
|
2596
|
+
var alignPad = (align) => {
|
|
2597
|
+
switch (align) {
|
|
2598
|
+
case "center":
|
|
2599
|
+
return padSides;
|
|
2600
|
+
case "right":
|
|
2601
|
+
return padLeft;
|
|
2602
|
+
default:
|
|
2603
|
+
return padRight;
|
|
2604
|
+
}
|
|
2605
|
+
};
|
|
2606
|
+
var Table = class {
|
|
2607
|
+
constructor(rows, options = {}) {
|
|
2608
|
+
this.rows = rows;
|
|
2609
|
+
this.columns = {};
|
|
2610
|
+
this.separator = options.separator ?? "|";
|
|
2611
|
+
this.align = options.align ?? "left";
|
|
2612
|
+
this.margin = options.margin ?? 0;
|
|
2613
|
+
this.string = "";
|
|
2614
|
+
if (options.title) this.title = options.title;
|
|
2615
|
+
if (options.columns) {
|
|
2616
|
+
for (const col of options.columns) {
|
|
2617
|
+
const column = new Column(col);
|
|
2618
|
+
if (!column.hidden) this.columns[column.key] = column;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
for (const row of this.rows) {
|
|
2622
|
+
for (const key of Object.keys(row)) {
|
|
2623
|
+
if (Object.keys(this.columns).length) {
|
|
2624
|
+
const column = this.columns[key];
|
|
2625
|
+
if (!column) continue;
|
|
2626
|
+
const cellLen = stringLength(column.value(row[key]));
|
|
2627
|
+
if (column.padding < cellLen) this.columns[key].padding = cellLen;
|
|
2628
|
+
} else {
|
|
2629
|
+
const keyLen = stringLength(key);
|
|
2630
|
+
const valLen = stringLength(String(row[key] ?? ""));
|
|
2631
|
+
this.columns[key] = new Column({ key, padding: Math.max(keyLen, valLen) });
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
if (options.meta) {
|
|
2636
|
+
this.meta = options.meta;
|
|
2637
|
+
for (const meta of options.meta) {
|
|
2638
|
+
for (const key of Object.keys(meta)) {
|
|
2639
|
+
const column = this.columns[key];
|
|
2640
|
+
if (!column) continue;
|
|
2641
|
+
const cellLen = stringLength(column.value(meta[key]));
|
|
2642
|
+
if (column.padding < cellLen) column.padding = cellLen;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
if (this.title) this.string += `${alignPad(this.align)(this.title, this.width)}
|
|
2647
|
+
|
|
2648
|
+
`;
|
|
2649
|
+
const keys = Object.keys(this.columns);
|
|
2650
|
+
let header = "";
|
|
2651
|
+
for (const [i, key] of keys.entries()) {
|
|
2652
|
+
const column = this.columns[key];
|
|
2653
|
+
const pad = alignPad(column.align ?? this.align);
|
|
2654
|
+
header += pad(column.title, column.padding + this.margin);
|
|
2655
|
+
if (i < keys.length - 1) header += this.separator;
|
|
2656
|
+
}
|
|
2657
|
+
const styled = typeof config.color === "number" ? cosmetic2.xterm(config.color) : config.color.startsWith("#") ? cosmetic2.hex(config.color) : cosmetic2[config.color];
|
|
2658
|
+
this.string += `${styled.underline.encoder(header)}
|
|
2659
|
+
`;
|
|
2660
|
+
for (const [ri, row] of this.rows.entries()) {
|
|
2661
|
+
for (const [ci, key] of keys.entries()) {
|
|
2662
|
+
const column = this.columns[key];
|
|
2663
|
+
const pad = alignPad(column.align ?? this.align);
|
|
2664
|
+
const raw = row[column.key];
|
|
2665
|
+
this.string += pad(column.value(raw == null ? "" : raw), column.padding + this.margin);
|
|
2666
|
+
if (ci < keys.length - 1) this.string += this.separator;
|
|
2667
|
+
}
|
|
2668
|
+
if (ri < this.rows.length - 1) this.string += "\n";
|
|
2669
|
+
}
|
|
2670
|
+
if (this.meta) {
|
|
2671
|
+
this.string += "\n\n";
|
|
2672
|
+
for (const [mi, meta] of this.meta.entries()) {
|
|
2673
|
+
for (const [ci, key] of keys.entries()) {
|
|
2674
|
+
const column = this.columns[key];
|
|
2675
|
+
const pad = alignPad(column.align ?? this.align);
|
|
2676
|
+
const raw = meta[column.key];
|
|
2677
|
+
this.string += pad(column.value(raw == null ? "" : raw), column.padding + this.margin);
|
|
2678
|
+
if (ci < keys.length - 1) this.string += this.separator;
|
|
2679
|
+
}
|
|
2680
|
+
if (mi < this.meta.length - 1) this.string += "\n";
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
print() {
|
|
2685
|
+
process.stdout.write(this.string + "\n");
|
|
2686
|
+
}
|
|
2687
|
+
get width() {
|
|
2688
|
+
let width = 0;
|
|
2689
|
+
for (const key of Object.keys(this.columns)) {
|
|
2690
|
+
if (!this.columns[key].hidden) width += this.columns[key].padding + this.margin + 1;
|
|
2691
|
+
}
|
|
2692
|
+
return width - 1;
|
|
2693
|
+
}
|
|
2694
|
+
};
|
|
2695
|
+
Table.left = "left";
|
|
2696
|
+
Table.center = "center";
|
|
2697
|
+
Table.right = "right";
|
|
2698
|
+
|
|
2699
|
+
// src/models/TermKit.ts
|
|
2700
|
+
var _TermKit = class _TermKit {
|
|
2701
|
+
static set defaults(obj) {
|
|
2702
|
+
_TermKit.commandDefaults = obj;
|
|
2703
|
+
}
|
|
2704
|
+
static setDefaults(obj) {
|
|
2705
|
+
_TermKit.commandDefaults = obj;
|
|
2706
|
+
}
|
|
2707
|
+
static command(name, variables, info) {
|
|
2708
|
+
const cmd = new Command(Object.assign({ name, variables, info }, _TermKit.commandDefaults));
|
|
2709
|
+
if (!_TermKit.base) _TermKit.base = cmd;
|
|
2710
|
+
return cmd;
|
|
2711
|
+
}
|
|
2712
|
+
static middleware(action) {
|
|
2713
|
+
return action;
|
|
2714
|
+
}
|
|
2715
|
+
static option(short, long, variables, info) {
|
|
2716
|
+
return new Option({ short, long, variables, info });
|
|
2717
|
+
}
|
|
2718
|
+
static parse(arr) {
|
|
2719
|
+
if (!_TermKit.base) throw new Error("No command defined");
|
|
2720
|
+
return _TermKit.base.parse(arr);
|
|
2721
|
+
}
|
|
2722
|
+
};
|
|
2723
|
+
_TermKit.base = null;
|
|
2724
|
+
_TermKit.commandDefaults = {};
|
|
2725
|
+
var TermKit = _TermKit;
|
|
2726
|
+
|
|
2727
|
+
// src/index.ts
|
|
2728
|
+
import { default as default2 } from "cosmetic";
|
|
2729
|
+
var base = null;
|
|
2730
|
+
var commandDefaults = {};
|
|
2731
|
+
var command = (name, variables, info) => {
|
|
2732
|
+
const cmd = new Command(Object.assign({ name, variables, info }, commandDefaults));
|
|
2733
|
+
if (!base) base = cmd;
|
|
2734
|
+
return cmd;
|
|
2735
|
+
};
|
|
2736
|
+
var middleware = (fn) => fn;
|
|
2737
|
+
var option = (short, long, variables, info) => new Option({ short, long, variables, info });
|
|
2738
|
+
var parse = async (arr) => {
|
|
2739
|
+
if (!base) throw new Error("No command defined");
|
|
2740
|
+
try {
|
|
2741
|
+
await base.parse(arr);
|
|
2742
|
+
} catch (err) {
|
|
2743
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2744
|
+
if (process.stderr.isTTY && config.glyphs) {
|
|
2745
|
+
process.stderr.write(`\x1B[31m\u2716\x1B[0m ${msg}
|
|
2746
|
+
`);
|
|
2747
|
+
} else {
|
|
2748
|
+
process.stderr.write(`Error: ${msg}
|
|
2749
|
+
`);
|
|
2750
|
+
}
|
|
2751
|
+
process.exit(1);
|
|
360
2752
|
}
|
|
361
|
-
};
|
|
362
|
-
_Termkit.base = null;
|
|
363
|
-
_Termkit.commandDefaults = {};
|
|
364
|
-
var Termkit = _Termkit;
|
|
365
|
-
|
|
366
|
-
// src/index.ts
|
|
367
|
-
var base = null;
|
|
368
|
-
var commandDefaults = {};
|
|
369
|
-
var command = (name, variables, info) => {
|
|
370
|
-
const cmd = new Command(Object.assign({ name, variables, info }, commandDefaults));
|
|
371
|
-
if (!base) base = cmd;
|
|
372
|
-
return cmd;
|
|
373
|
-
};
|
|
374
|
-
var middleware = (fn) => fn;
|
|
375
|
-
var option = (short, long, variables, info) => new Option({ short, long, variables, info });
|
|
376
|
-
var parse = (arr) => {
|
|
377
|
-
if (!base) throw new Error("No command defined");
|
|
378
|
-
return base.parse(arr);
|
|
379
2753
|
};
|
|
380
2754
|
var setDefaults = (data) => {
|
|
381
2755
|
commandDefaults = data;
|
|
382
2756
|
};
|
|
383
2757
|
export {
|
|
2758
|
+
Bar,
|
|
2759
|
+
Chart_exports as Chart,
|
|
2760
|
+
default2 as Color,
|
|
2761
|
+
Column,
|
|
384
2762
|
Command,
|
|
2763
|
+
Input,
|
|
2764
|
+
Log,
|
|
2765
|
+
MultiBar,
|
|
2766
|
+
MultiSelect,
|
|
385
2767
|
Option,
|
|
386
|
-
|
|
2768
|
+
Scrollbox,
|
|
2769
|
+
Select,
|
|
2770
|
+
Spinner,
|
|
2771
|
+
Table,
|
|
2772
|
+
TermKit,
|
|
387
2773
|
Variable,
|
|
388
2774
|
command,
|
|
2775
|
+
configure,
|
|
2776
|
+
confirm,
|
|
2777
|
+
input,
|
|
2778
|
+
log,
|
|
2779
|
+
markup,
|
|
389
2780
|
middleware,
|
|
2781
|
+
multiSelect,
|
|
390
2782
|
option,
|
|
2783
|
+
padLeft,
|
|
2784
|
+
padRight,
|
|
2785
|
+
padSides,
|
|
391
2786
|
parse,
|
|
392
|
-
|
|
2787
|
+
scrollbox,
|
|
2788
|
+
select,
|
|
2789
|
+
setDefaults,
|
|
2790
|
+
stringLength,
|
|
2791
|
+
truncate,
|
|
2792
|
+
wrap
|
|
393
2793
|
};
|