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