@heinrichb/console-toolkit 1.0.9 → 1.0.13
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 +320 -162
- package/dist/components/progress.d.ts +10 -0
- package/dist/components/table.d.ts +31 -0
- package/dist/core/builders.d.ts +25 -0
- package/dist/core/layout.d.ts +1 -0
- package/dist/core/printer.d.ts +18 -2
- package/dist/core/style.d.ts +22 -10
- package/dist/core/types.d.ts +15 -1
- package/dist/core/utils.d.ts +9 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +313 -92
- package/dist/index.min.js +2 -2
- package/dist/presets/ascii.d.ts +3 -1
- package/dist/presets/gradients.d.ts +6 -0
- package/package.json +35 -13
package/dist/core/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type StandardColor = "black" | "red" | "green" | "yellow" | "blue" | "mag
|
|
|
5
5
|
/**
|
|
6
6
|
* Text style modifiers.
|
|
7
7
|
*/
|
|
8
|
-
export type StyleModifier = "bold" | "dim" | "italic" | "underline" | "
|
|
8
|
+
export type StyleModifier = "bold" | "dim" | "italic" | "underline" | "hidden" | "inverse" | "strikethrough";
|
|
9
9
|
/**
|
|
10
10
|
* A valid Hex color string (e.g., "#FF0000").
|
|
11
11
|
*/
|
|
@@ -14,6 +14,14 @@ export type HexColor = `#${string}`;
|
|
|
14
14
|
* A color can be a standard color name or a hex color string.
|
|
15
15
|
*/
|
|
16
16
|
export type Color = StandardColor | HexColor;
|
|
17
|
+
/**
|
|
18
|
+
* Represents an RGB color value.
|
|
19
|
+
*/
|
|
20
|
+
export interface RGB {
|
|
21
|
+
r: number;
|
|
22
|
+
g: number;
|
|
23
|
+
b: number;
|
|
24
|
+
}
|
|
17
25
|
/**
|
|
18
26
|
* Represents the style configuration for a text segment, line, or block.
|
|
19
27
|
*/
|
|
@@ -24,6 +32,12 @@ export interface PrintStyle {
|
|
|
24
32
|
* - An array of colors applies a gradient.
|
|
25
33
|
*/
|
|
26
34
|
color?: Color | Color[];
|
|
35
|
+
/**
|
|
36
|
+
* The background color to apply.
|
|
37
|
+
* - A single color (string) applies a solid background.
|
|
38
|
+
* - An array of colors applies a background gradient.
|
|
39
|
+
*/
|
|
40
|
+
bgColor?: Color | Color[];
|
|
27
41
|
/**
|
|
28
42
|
* A list of style modifiers (e.g., bold, italic) to apply.
|
|
29
43
|
*/
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -17,9 +17,16 @@ export declare function computeMaxWidth(lines: PrintLine[]): number;
|
|
|
17
17
|
/**
|
|
18
18
|
* Pads a PrintLine to a target width by adding an empty segment at the end.
|
|
19
19
|
*
|
|
20
|
-
* @param
|
|
20
|
+
* @param inputLine - The line to pad.
|
|
21
21
|
* @param targetWidth - The desired minimum width.
|
|
22
22
|
* @param padStyle - The style to apply to the padding spaces.
|
|
23
23
|
* @returns A new PrintLine with padding added if necessary.
|
|
24
24
|
*/
|
|
25
|
-
export declare function padLine(
|
|
25
|
+
export declare function padLine(inputLine: PrintLine, targetWidth: number, padStyle?: PrintStyle): PrintLine;
|
|
26
|
+
/**
|
|
27
|
+
* Strips all ANSI escape sequences from a string, returning plain text.
|
|
28
|
+
*
|
|
29
|
+
* @param text - The string potentially containing ANSI codes.
|
|
30
|
+
* @returns The plain text with all ANSI sequences removed.
|
|
31
|
+
*/
|
|
32
|
+
export declare function stripAnsi(text: string): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export * from "./core/types";
|
|
2
2
|
export * from "./core/style";
|
|
3
3
|
export * from "./core/utils";
|
|
4
|
+
export * from "./core/builders";
|
|
4
5
|
export * from "./core/printer";
|
|
5
6
|
export * from "./core/layout";
|
|
6
7
|
export * from "./components/progress";
|
|
7
8
|
export * from "./components/spinner";
|
|
9
|
+
export * from "./components/table";
|
|
8
10
|
export * from "./presets/ascii";
|
|
11
|
+
export * from "./presets/gradients";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/core/style.ts
|
|
2
2
|
var ESC = "\x1B";
|
|
3
3
|
var RESET = `${ESC}[0m`;
|
|
4
|
-
var STANDARD_COLORS = {
|
|
4
|
+
var STANDARD_COLORS = Object.assign(Object.create(null), {
|
|
5
5
|
black: "#000000",
|
|
6
6
|
red: "#EF4444",
|
|
7
7
|
green: "#10B981",
|
|
@@ -12,9 +12,8 @@ var STANDARD_COLORS = {
|
|
|
12
12
|
white: "#FFFFFF",
|
|
13
13
|
gray: "#6B7280",
|
|
14
14
|
grey: "#6B7280"
|
|
15
|
-
};
|
|
16
|
-
var MODIFIER_CODES = {
|
|
17
|
-
default: "0",
|
|
15
|
+
});
|
|
16
|
+
var MODIFIER_CODES = Object.assign(Object.create(null), {
|
|
18
17
|
bold: "1",
|
|
19
18
|
dim: "2",
|
|
20
19
|
italic: "3",
|
|
@@ -22,7 +21,7 @@ var MODIFIER_CODES = {
|
|
|
22
21
|
inverse: "7",
|
|
23
22
|
hidden: "8",
|
|
24
23
|
strikethrough: "9"
|
|
25
|
-
};
|
|
24
|
+
});
|
|
26
25
|
function colorToHex(color) {
|
|
27
26
|
if (color.startsWith("#"))
|
|
28
27
|
return color;
|
|
@@ -44,11 +43,17 @@ function hexToRgb(hex) {
|
|
|
44
43
|
function rgbToAnsi(r, g, b) {
|
|
45
44
|
return `${ESC}[38;2;${r};${g};${b}m`;
|
|
46
45
|
}
|
|
46
|
+
function rgbToBgAnsi(r, g, b) {
|
|
47
|
+
return `${ESC}[48;2;${r};${g};${b}m`;
|
|
48
|
+
}
|
|
47
49
|
function resolveColorToAnsi(color) {
|
|
48
|
-
const
|
|
49
|
-
const { r, g, b } = hexToRgb(hex);
|
|
50
|
+
const { r, g, b } = resolveColorToRgb(color);
|
|
50
51
|
return rgbToAnsi(r, g, b);
|
|
51
52
|
}
|
|
53
|
+
function resolveColorToRgb(color) {
|
|
54
|
+
const hex = colorToHex(color);
|
|
55
|
+
return hexToRgb(hex);
|
|
56
|
+
}
|
|
52
57
|
function resolveModifiersToAnsi(modifiers) {
|
|
53
58
|
if (!modifiers || modifiers.length === 0)
|
|
54
59
|
return "";
|
|
@@ -70,22 +75,38 @@ function interpolateHex(color1, color2, factor) {
|
|
|
70
75
|
const b = c1.b + f * (c2.b - c1.b);
|
|
71
76
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
72
77
|
}
|
|
73
|
-
function
|
|
74
|
-
|
|
78
|
+
function gradientSegment(colorCount, factor) {
|
|
79
|
+
const f = Math.max(0, Math.min(1, factor));
|
|
80
|
+
const segmentLength = 1 / (colorCount - 1);
|
|
81
|
+
const index = Math.min(Math.floor(f / segmentLength), colorCount - 2);
|
|
82
|
+
return { index, factor: (f - index * segmentLength) / segmentLength };
|
|
75
83
|
}
|
|
76
|
-
function
|
|
84
|
+
function getGradientAnsiFromRgb(colors, factor, toAnsi) {
|
|
77
85
|
if (colors.length === 0)
|
|
78
86
|
return "";
|
|
79
87
|
if (colors.length === 1)
|
|
80
|
-
return
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
return toAnsi(colors[0].r, colors[0].g, colors[0].b);
|
|
89
|
+
const seg = gradientSegment(colors.length, factor);
|
|
90
|
+
const c1 = colors[seg.index];
|
|
91
|
+
const c2 = colors[seg.index + 1];
|
|
92
|
+
const r = Math.round(c1.r + seg.factor * (c2.r - c1.r));
|
|
93
|
+
const g = Math.round(c1.g + seg.factor * (c2.g - c1.g));
|
|
94
|
+
const b = Math.round(c1.b + seg.factor * (c2.b - c1.b));
|
|
95
|
+
return toAnsi(r, g, b);
|
|
96
|
+
}
|
|
97
|
+
function getGradientColorFromRgb(colors, factor) {
|
|
98
|
+
return getGradientAnsiFromRgb(colors, factor, rgbToAnsi);
|
|
99
|
+
}
|
|
100
|
+
function getGradientBgColorFromRgb(colors, factor) {
|
|
101
|
+
return getGradientAnsiFromRgb(colors, factor, rgbToBgAnsi);
|
|
102
|
+
}
|
|
103
|
+
function interpolateGradient(colors, factor) {
|
|
104
|
+
if (colors.length === 0)
|
|
105
|
+
return "#FFFFFF";
|
|
106
|
+
if (colors.length === 1)
|
|
107
|
+
return colorToHex(colors[0]);
|
|
108
|
+
const seg = gradientSegment(colors.length, factor);
|
|
109
|
+
return interpolateHex(colorToHex(colors[seg.index]), colorToHex(colors[seg.index + 1]), seg.factor);
|
|
89
110
|
}
|
|
90
111
|
function mergeStyles(parent, child) {
|
|
91
112
|
if (!parent && !child)
|
|
@@ -94,10 +115,17 @@ function mergeStyles(parent, child) {
|
|
|
94
115
|
return child ?? {};
|
|
95
116
|
if (!child)
|
|
96
117
|
return parent;
|
|
97
|
-
const
|
|
118
|
+
const parentMods = parent.modifiers ?? [];
|
|
119
|
+
const childMods = child.modifiers ?? [];
|
|
120
|
+
const mergedModifiers = [...parentMods];
|
|
121
|
+
for (const mod of childMods) {
|
|
122
|
+
if (!mergedModifiers.includes(mod))
|
|
123
|
+
mergedModifiers.push(mod);
|
|
124
|
+
}
|
|
98
125
|
return {
|
|
99
126
|
modifiers: mergedModifiers,
|
|
100
|
-
color: child.color ?? parent.color
|
|
127
|
+
color: child.color ?? parent.color,
|
|
128
|
+
bgColor: child.bgColor ?? parent.bgColor
|
|
101
129
|
};
|
|
102
130
|
}
|
|
103
131
|
function resolveStyle(style, gradientFactor = 0) {
|
|
@@ -109,33 +137,53 @@ function resolveStyle(style, gradientFactor = 0) {
|
|
|
109
137
|
}
|
|
110
138
|
if (style.color) {
|
|
111
139
|
if (Array.isArray(style.color)) {
|
|
112
|
-
const
|
|
113
|
-
ansi +=
|
|
140
|
+
const rgbColors = style.color.map(resolveColorToRgb);
|
|
141
|
+
ansi += getGradientColorFromRgb(rgbColors, gradientFactor);
|
|
114
142
|
} else {
|
|
115
143
|
ansi += resolveColorToAnsi(style.color);
|
|
116
144
|
}
|
|
117
145
|
}
|
|
146
|
+
if (style.bgColor) {
|
|
147
|
+
if (Array.isArray(style.bgColor)) {
|
|
148
|
+
const bgRgbColors = style.bgColor.map(resolveColorToRgb);
|
|
149
|
+
ansi += getGradientBgColorFromRgb(bgRgbColors, gradientFactor);
|
|
150
|
+
} else {
|
|
151
|
+
const { r, g, b } = resolveColorToRgb(style.bgColor);
|
|
152
|
+
ansi += rgbToBgAnsi(r, g, b);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
118
155
|
return ansi;
|
|
119
156
|
}
|
|
157
|
+
// src/core/builders.ts
|
|
158
|
+
function segment(text, style) {
|
|
159
|
+
return { text, style };
|
|
160
|
+
}
|
|
161
|
+
function line(segments = [], style) {
|
|
162
|
+
return { segments, style };
|
|
163
|
+
}
|
|
164
|
+
function block(lines = [], style) {
|
|
165
|
+
return { lines, style };
|
|
166
|
+
}
|
|
167
|
+
|
|
120
168
|
// src/core/utils.ts
|
|
121
|
-
function getLineLength(
|
|
122
|
-
return
|
|
169
|
+
function getLineLength(line2) {
|
|
170
|
+
return line2.segments.reduce((acc, seg) => acc + seg.text.length, 0);
|
|
123
171
|
}
|
|
124
172
|
function computeMaxWidth(lines) {
|
|
125
|
-
return lines.
|
|
173
|
+
return lines.reduce((max, l) => Math.max(max, getLineLength(l)), 0);
|
|
126
174
|
}
|
|
127
|
-
function padLine(
|
|
128
|
-
const currentLength = getLineLength(
|
|
175
|
+
function padLine(inputLine, targetWidth, padStyle) {
|
|
176
|
+
const currentLength = getLineLength(inputLine);
|
|
129
177
|
if (currentLength < targetWidth) {
|
|
130
|
-
return
|
|
131
|
-
segments: [...line.segments, { text: " ".repeat(targetWidth - currentLength), style: padStyle }]
|
|
132
|
-
};
|
|
178
|
+
return line([...inputLine.segments, segment(" ".repeat(targetWidth - currentLength), padStyle)], inputLine.style);
|
|
133
179
|
}
|
|
134
|
-
return
|
|
180
|
+
return inputLine;
|
|
181
|
+
}
|
|
182
|
+
var ANSI_REGEX = /\x1b\[[0-9;]*m/g;
|
|
183
|
+
function stripAnsi(text) {
|
|
184
|
+
return text.replace(ANSI_REGEX, "");
|
|
135
185
|
}
|
|
136
186
|
// src/core/printer.ts
|
|
137
|
-
var ESC2 = "\x1B";
|
|
138
|
-
|
|
139
187
|
class Printer {
|
|
140
188
|
linesRendered = 0;
|
|
141
189
|
isLive;
|
|
@@ -147,7 +195,7 @@ class Printer {
|
|
|
147
195
|
getClearSequence() {
|
|
148
196
|
if (!this.isLive || this.linesRendered === 0)
|
|
149
197
|
return "";
|
|
150
|
-
return `${
|
|
198
|
+
return `${ESC}[1A${ESC}[2K\r`.repeat(this.linesRendered);
|
|
151
199
|
}
|
|
152
200
|
clear() {
|
|
153
201
|
if (this.linesRendered > 0) {
|
|
@@ -155,6 +203,14 @@ class Printer {
|
|
|
155
203
|
this.linesRendered = 0;
|
|
156
204
|
}
|
|
157
205
|
}
|
|
206
|
+
renderToString(data) {
|
|
207
|
+
if (data) {
|
|
208
|
+
this.data = data;
|
|
209
|
+
}
|
|
210
|
+
if (!this.data)
|
|
211
|
+
return "";
|
|
212
|
+
return this.renderBlock(this.data);
|
|
213
|
+
}
|
|
158
214
|
print(data) {
|
|
159
215
|
if (data) {
|
|
160
216
|
this.data = data;
|
|
@@ -162,51 +218,67 @@ class Printer {
|
|
|
162
218
|
if (!this.data) {
|
|
163
219
|
return;
|
|
164
220
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
221
|
+
const output = this.getClearSequence() + this.renderBlock(this.data);
|
|
222
|
+
process.stdout.write(output);
|
|
223
|
+
this.linesRendered = this.data.lines.length;
|
|
224
|
+
}
|
|
225
|
+
renderBlock(blockData) {
|
|
226
|
+
let output = "";
|
|
227
|
+
const lines = blockData.lines;
|
|
228
|
+
const blockStyle = blockData.style ?? {};
|
|
229
|
+
lines.forEach((ln, lineIndex) => {
|
|
230
|
+
output += this.renderLine(ln, lineIndex, lines.length, blockStyle);
|
|
170
231
|
output += `
|
|
171
232
|
`;
|
|
172
233
|
});
|
|
173
|
-
|
|
174
|
-
this.linesRendered = lines.length;
|
|
234
|
+
return output;
|
|
175
235
|
}
|
|
176
|
-
|
|
177
|
-
|
|
236
|
+
resolveBlockStyleForLine(blockStyle, lineIndex, totalLines) {
|
|
237
|
+
return {
|
|
238
|
+
modifiers: blockStyle.modifiers,
|
|
239
|
+
color: this.resolveGradientForLine(blockStyle.color, lineIndex, totalLines),
|
|
240
|
+
bgColor: this.resolveGradientForLine(blockStyle.bgColor, lineIndex, totalLines)
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
resolveGradientForLine(color, lineIndex, totalLines) {
|
|
244
|
+
if (!color)
|
|
178
245
|
return;
|
|
179
|
-
if (Array.isArray(
|
|
246
|
+
if (Array.isArray(color)) {
|
|
180
247
|
if (totalLines <= 1)
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
const factor = lineIndex / (totalLines - 1);
|
|
184
|
-
const f = Math.max(0, Math.min(1, factor));
|
|
185
|
-
const segmentLength = 1 / (colors.length - 1);
|
|
186
|
-
const segmentIndex = Math.min(Math.floor(f / segmentLength), colors.length - 2);
|
|
187
|
-
const segmentFactor = (f - segmentIndex * segmentLength) / segmentLength;
|
|
188
|
-
const c1 = colors[segmentIndex];
|
|
189
|
-
const c2 = colors[segmentIndex + 1];
|
|
190
|
-
return interpolateColor(c1, c2, segmentFactor);
|
|
248
|
+
return color[0];
|
|
249
|
+
return interpolateGradient(color, lineIndex / (totalLines - 1));
|
|
191
250
|
}
|
|
192
|
-
return
|
|
251
|
+
return color;
|
|
193
252
|
}
|
|
194
|
-
renderLine(
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
color: blockColorForLine
|
|
199
|
-
};
|
|
200
|
-
const effectiveLineStyle = mergeStyles(baseLineStyle, line.style);
|
|
201
|
-
const totalChars = line.segments.reduce((acc, seg) => acc + seg.text.length, 0);
|
|
253
|
+
renderLine(line2, lineIndex, totalLines, parentBlockStyle) {
|
|
254
|
+
const baseLineStyle = this.resolveBlockStyleForLine(parentBlockStyle, lineIndex, totalLines);
|
|
255
|
+
const effectiveLineStyle = mergeStyles(baseLineStyle, line2.style);
|
|
256
|
+
const totalChars = line2.segments.reduce((acc, seg) => acc + seg.text.length, 0);
|
|
202
257
|
let currentCharIndex = 0;
|
|
203
258
|
let lineOutput = "";
|
|
204
|
-
|
|
259
|
+
line2.segments.forEach((seg) => {
|
|
205
260
|
const effectiveSegmentStyle = mergeStyles(effectiveLineStyle, seg.style);
|
|
206
|
-
|
|
207
|
-
|
|
261
|
+
const hasFgGradient = Array.isArray(effectiveSegmentStyle.color);
|
|
262
|
+
const hasBgGradient = Array.isArray(effectiveSegmentStyle.bgColor);
|
|
263
|
+
if (hasFgGradient || hasBgGradient) {
|
|
208
264
|
const text = seg.text;
|
|
209
265
|
const isGlobalGradient = effectiveSegmentStyle.color === effectiveLineStyle.color;
|
|
266
|
+
let fgRgbColors;
|
|
267
|
+
let solidFgAnsi = "";
|
|
268
|
+
if (hasFgGradient) {
|
|
269
|
+
fgRgbColors = effectiveSegmentStyle.color.map(resolveColorToRgb);
|
|
270
|
+
} else if (effectiveSegmentStyle.color) {
|
|
271
|
+
const { r, g, b } = resolveColorToRgb(effectiveSegmentStyle.color);
|
|
272
|
+
solidFgAnsi = rgbToAnsi(r, g, b);
|
|
273
|
+
}
|
|
274
|
+
let bgRgbColors;
|
|
275
|
+
let solidBgAnsi = "";
|
|
276
|
+
if (hasBgGradient) {
|
|
277
|
+
bgRgbColors = effectiveSegmentStyle.bgColor.map(resolveColorToRgb);
|
|
278
|
+
} else if (effectiveSegmentStyle.bgColor) {
|
|
279
|
+
const { r, g, b } = resolveColorToRgb(effectiveSegmentStyle.bgColor);
|
|
280
|
+
solidBgAnsi = rgbToBgAnsi(r, g, b);
|
|
281
|
+
}
|
|
210
282
|
const modifiersAnsi = resolveModifiersToAnsi(effectiveSegmentStyle.modifiers);
|
|
211
283
|
for (let i = 0;i < text.length; i++) {
|
|
212
284
|
let factor = 0;
|
|
@@ -215,8 +287,9 @@ class Printer {
|
|
|
215
287
|
} else if (!isGlobalGradient && text.length > 1) {
|
|
216
288
|
factor = i / (text.length - 1);
|
|
217
289
|
}
|
|
218
|
-
const
|
|
219
|
-
|
|
290
|
+
const fgAnsi = fgRgbColors ? getGradientColorFromRgb(fgRgbColors, factor) : solidFgAnsi;
|
|
291
|
+
const bgAnsi = bgRgbColors ? getGradientBgColorFromRgb(bgRgbColors, factor) : solidBgAnsi;
|
|
292
|
+
lineOutput += `${modifiersAnsi}${fgAnsi}${bgAnsi}${text[i]}`;
|
|
220
293
|
}
|
|
221
294
|
lineOutput += RESET;
|
|
222
295
|
} else {
|
|
@@ -232,7 +305,7 @@ class Printer {
|
|
|
232
305
|
function mergeColumns(columns, separator = " ", defaultStyle, widths) {
|
|
233
306
|
if (columns.length === 0)
|
|
234
307
|
return [];
|
|
235
|
-
const maxLines =
|
|
308
|
+
const maxLines = columns.reduce((max, c) => Math.max(max, c.length), 0);
|
|
236
309
|
const colWidths = columns.map((col, i) => {
|
|
237
310
|
if (widths?.[i] !== undefined)
|
|
238
311
|
return widths[i];
|
|
@@ -240,24 +313,24 @@ function mergeColumns(columns, separator = " ", defaultStyle, widths) {
|
|
|
240
313
|
});
|
|
241
314
|
const output = [];
|
|
242
315
|
for (let i = 0;i < maxLines; i++) {
|
|
243
|
-
|
|
316
|
+
const segments = [];
|
|
244
317
|
for (let j = 0;j < columns.length; j++) {
|
|
245
|
-
const
|
|
318
|
+
const currentLine = columns[j][i] || line();
|
|
246
319
|
if (j < columns.length - 1) {
|
|
247
|
-
const padded = padLine(
|
|
248
|
-
segments
|
|
320
|
+
const padded = padLine(currentLine, colWidths[j], defaultStyle);
|
|
321
|
+
segments.push(...padded.segments, segment(separator, defaultStyle));
|
|
249
322
|
} else {
|
|
250
|
-
segments
|
|
323
|
+
segments.push(...currentLine.segments);
|
|
251
324
|
}
|
|
252
325
|
}
|
|
253
|
-
output.push(
|
|
326
|
+
output.push(line(segments));
|
|
254
327
|
}
|
|
255
328
|
return output;
|
|
256
329
|
}
|
|
257
330
|
function printColumns(columns, options = {}) {
|
|
258
|
-
const { widths, separator = " ", printer = new Printer } = options;
|
|
259
|
-
const mergedLines = mergeColumns(columns, separator,
|
|
260
|
-
printer.print(
|
|
331
|
+
const { widths, separator = " ", defaultStyle, printer = new Printer } = options;
|
|
332
|
+
const mergedLines = mergeColumns(columns, separator, defaultStyle, widths);
|
|
333
|
+
printer.print(block(mergedLines));
|
|
261
334
|
}
|
|
262
335
|
// src/components/progress.ts
|
|
263
336
|
function createProgressBar(options) {
|
|
@@ -275,7 +348,9 @@ function createProgressBar(options) {
|
|
|
275
348
|
startChar = "[",
|
|
276
349
|
endChar = "]",
|
|
277
350
|
fillChar = "█",
|
|
351
|
+
completeChar,
|
|
278
352
|
emptyChar = "░",
|
|
353
|
+
completeStyle,
|
|
279
354
|
showPercentage = true,
|
|
280
355
|
formatPercentage
|
|
281
356
|
} = options;
|
|
@@ -286,27 +361,29 @@ function createProgressBar(options) {
|
|
|
286
361
|
const resolvedStartStyle = startStyle ?? resolvedBracketStyle;
|
|
287
362
|
const resolvedEndStyle = endStyle ?? resolvedBracketStyle;
|
|
288
363
|
const resolvedBarStyle = barStyle ?? style;
|
|
289
|
-
const
|
|
364
|
+
const isComplete = p >= 1;
|
|
365
|
+
const resolvedFillStyle = isComplete ? completeStyle ?? fillStyle ?? resolvedBarStyle : fillStyle ?? resolvedBarStyle;
|
|
290
366
|
const resolvedEmptyStyle = emptyStyle ?? resolvedBarStyle;
|
|
291
367
|
const resolvedPercentageStyle = percentageStyle ?? style;
|
|
292
368
|
const segments = [];
|
|
293
369
|
if (startChar) {
|
|
294
|
-
segments.push(
|
|
370
|
+
segments.push(segment(startChar, resolvedStartStyle));
|
|
295
371
|
}
|
|
372
|
+
const effectiveFillChar = isComplete ? completeChar ?? fillChar : fillChar;
|
|
296
373
|
if (filledWidth > 0) {
|
|
297
|
-
segments.push(
|
|
374
|
+
segments.push(segment(effectiveFillChar.repeat(filledWidth), resolvedFillStyle));
|
|
298
375
|
}
|
|
299
376
|
if (emptyWidth > 0) {
|
|
300
|
-
segments.push(
|
|
377
|
+
segments.push(segment(emptyChar.repeat(emptyWidth), resolvedEmptyStyle));
|
|
301
378
|
}
|
|
302
379
|
if (endChar) {
|
|
303
|
-
segments.push(
|
|
380
|
+
segments.push(segment(endChar, resolvedEndStyle));
|
|
304
381
|
}
|
|
305
382
|
if (showPercentage) {
|
|
306
383
|
const percentageText = formatPercentage ? formatPercentage(p) : ` ${Math.round(p * 100)}%`;
|
|
307
|
-
segments.push(
|
|
384
|
+
segments.push(segment(percentageText, resolvedPercentageStyle));
|
|
308
385
|
}
|
|
309
|
-
return
|
|
386
|
+
return line(segments);
|
|
310
387
|
}
|
|
311
388
|
// src/components/spinner.ts
|
|
312
389
|
var SPINNERS = {
|
|
@@ -333,8 +410,133 @@ class Spinner {
|
|
|
333
410
|
return this.frames[index];
|
|
334
411
|
}
|
|
335
412
|
}
|
|
413
|
+
// src/components/table.ts
|
|
414
|
+
var BORDERS = {
|
|
415
|
+
single: {
|
|
416
|
+
tl: "┌",
|
|
417
|
+
t: "─",
|
|
418
|
+
tr: "┐",
|
|
419
|
+
l: "│",
|
|
420
|
+
r: "│",
|
|
421
|
+
bl: "└",
|
|
422
|
+
b: "─",
|
|
423
|
+
br: "┘",
|
|
424
|
+
ml: "├",
|
|
425
|
+
m: "─",
|
|
426
|
+
mr: "┤",
|
|
427
|
+
tj: "┬",
|
|
428
|
+
bj: "┴",
|
|
429
|
+
mj: "┼"
|
|
430
|
+
},
|
|
431
|
+
double: {
|
|
432
|
+
tl: "╔",
|
|
433
|
+
t: "═",
|
|
434
|
+
tr: "╗",
|
|
435
|
+
l: "║",
|
|
436
|
+
r: "║",
|
|
437
|
+
bl: "╚",
|
|
438
|
+
b: "═",
|
|
439
|
+
br: "╝",
|
|
440
|
+
ml: "╠",
|
|
441
|
+
m: "═",
|
|
442
|
+
mr: "╣",
|
|
443
|
+
tj: "╦",
|
|
444
|
+
bj: "╩",
|
|
445
|
+
mj: "╬"
|
|
446
|
+
},
|
|
447
|
+
rounded: {
|
|
448
|
+
tl: "╭",
|
|
449
|
+
t: "─",
|
|
450
|
+
tr: "╮",
|
|
451
|
+
l: "│",
|
|
452
|
+
r: "│",
|
|
453
|
+
bl: "╰",
|
|
454
|
+
b: "─",
|
|
455
|
+
br: "╯",
|
|
456
|
+
ml: "├",
|
|
457
|
+
m: "─",
|
|
458
|
+
mr: "┤",
|
|
459
|
+
tj: "┬",
|
|
460
|
+
bj: "┴",
|
|
461
|
+
mj: "┼"
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
function buildBorderLine(left, fill, junction, right, colWidths, padding, borderStyle) {
|
|
465
|
+
const parts = [left];
|
|
466
|
+
for (let i = 0;i < colWidths.length; i++) {
|
|
467
|
+
parts.push(fill.repeat(colWidths[i] + padding * 2));
|
|
468
|
+
if (i < colWidths.length - 1)
|
|
469
|
+
parts.push(junction);
|
|
470
|
+
}
|
|
471
|
+
parts.push(right);
|
|
472
|
+
return line([segment(parts.join(""), borderStyle)]);
|
|
473
|
+
}
|
|
474
|
+
function buildDataRow(cells, colWidths, padding, colCount, borderChar, cellStyle, borderStyle) {
|
|
475
|
+
const segments = [];
|
|
476
|
+
segments.push(segment(borderChar, borderStyle));
|
|
477
|
+
for (let i = 0;i < colCount; i++) {
|
|
478
|
+
const cellText = cells[i] ?? "";
|
|
479
|
+
const padded = " ".repeat(padding) + cellText.padEnd(colWidths[i]) + " ".repeat(padding);
|
|
480
|
+
segments.push(segment(padded, cellStyle));
|
|
481
|
+
if (i < colCount - 1) {
|
|
482
|
+
segments.push(segment(borderChar, borderStyle));
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
segments.push(segment(borderChar, borderStyle));
|
|
486
|
+
return line(segments);
|
|
487
|
+
}
|
|
488
|
+
function createTable(options) {
|
|
489
|
+
const { headers, rows, style, headerStyle, borderStyle, border = "single", columnWidths, cellPadding = 1 } = options;
|
|
490
|
+
const colCount = rows.reduce((max, r) => Math.max(max, r.length), headers?.length ?? 0);
|
|
491
|
+
if (colCount === 0)
|
|
492
|
+
return [];
|
|
493
|
+
const colWidths = [];
|
|
494
|
+
for (let i = 0;i < colCount; i++) {
|
|
495
|
+
if (columnWidths?.[i] !== undefined) {
|
|
496
|
+
colWidths.push(columnWidths[i]);
|
|
497
|
+
} else {
|
|
498
|
+
const headerWidth = headers?.[i]?.length ?? 0;
|
|
499
|
+
const maxRowWidth = rows.reduce((max, row) => Math.max(max, row[i]?.length ?? 0), 0);
|
|
500
|
+
colWidths.push(Math.max(headerWidth, maxRowWidth));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (border === "none") {
|
|
504
|
+
return buildNoBorderTable(headers, rows, colWidths, cellPadding, colCount, style, headerStyle);
|
|
505
|
+
}
|
|
506
|
+
const chars = BORDERS[border];
|
|
507
|
+
const output = [];
|
|
508
|
+
output.push(buildBorderLine(chars.tl, chars.t, chars.tj, chars.tr, colWidths, cellPadding, borderStyle));
|
|
509
|
+
if (headers) {
|
|
510
|
+
output.push(buildDataRow(headers, colWidths, cellPadding, colCount, chars.l, headerStyle ?? style, borderStyle));
|
|
511
|
+
output.push(buildBorderLine(chars.ml, chars.m, chars.mj, chars.mr, colWidths, cellPadding, borderStyle));
|
|
512
|
+
}
|
|
513
|
+
for (const row of rows) {
|
|
514
|
+
output.push(buildDataRow(row, colWidths, cellPadding, colCount, chars.l, style, borderStyle));
|
|
515
|
+
}
|
|
516
|
+
output.push(buildBorderLine(chars.bl, chars.b, chars.bj, chars.br, colWidths, cellPadding, borderStyle));
|
|
517
|
+
return output;
|
|
518
|
+
}
|
|
519
|
+
function buildNoBorderTable(headers, rows, colWidths, padding, colCount, style, headerStyle) {
|
|
520
|
+
const output = [];
|
|
521
|
+
const space = " ".repeat(padding);
|
|
522
|
+
function buildRow(cells, cellStyle) {
|
|
523
|
+
const segments = [];
|
|
524
|
+
for (let i = 0;i < colCount; i++) {
|
|
525
|
+
const cellText = cells[i] ?? "";
|
|
526
|
+
segments.push(segment(space + cellText.padEnd(colWidths[i]) + space, cellStyle));
|
|
527
|
+
}
|
|
528
|
+
return line(segments);
|
|
529
|
+
}
|
|
530
|
+
if (headers) {
|
|
531
|
+
output.push(buildRow(headers, headerStyle ?? style));
|
|
532
|
+
}
|
|
533
|
+
for (const row of rows) {
|
|
534
|
+
output.push(buildRow(row, style));
|
|
535
|
+
}
|
|
536
|
+
return output;
|
|
537
|
+
}
|
|
336
538
|
// src/presets/ascii.ts
|
|
337
|
-
function getDragon(
|
|
539
|
+
function getDragon(colors = ["#EF4444", "#F59E0B"]) {
|
|
338
540
|
const rawDragon = [
|
|
339
541
|
" ^ ^",
|
|
340
542
|
" / \\ //\\",
|
|
@@ -356,30 +558,49 @@ function getDragon(startColor = "#EF4444", endColor = "#F59E0B") {
|
|
|
356
558
|
];
|
|
357
559
|
return rawDragon.map((text, i) => {
|
|
358
560
|
const factor = rawDragon.length <= 1 ? 0 : i / (rawDragon.length - 1);
|
|
359
|
-
const
|
|
360
|
-
return
|
|
561
|
+
const color = interpolateGradient(colors, factor);
|
|
562
|
+
return line([segment(text, { color })]);
|
|
361
563
|
});
|
|
362
564
|
}
|
|
565
|
+
// src/presets/gradients.ts
|
|
566
|
+
var GRADIENTS = {
|
|
567
|
+
rainbow: ["#EF4444", "#F59E0B", "#10B981", "#06B6D4", "#3B82F6", "#8B5CF6"],
|
|
568
|
+
ocean: ["#1E3A5F", "#0E7490", "#06B6D4", "#67E8F9"],
|
|
569
|
+
fire: ["#7F1D1D", "#EF4444", "#F59E0B", "#FDE047"],
|
|
570
|
+
sunset: ["#7C3AED", "#EC4899", "#F97316", "#FBBF24"],
|
|
571
|
+
forest: ["#064E3B", "#10B981", "#84CC16", "#BEF264"],
|
|
572
|
+
monochrome: ["#000000", "#6B7280", "#FFFFFF"]
|
|
573
|
+
};
|
|
363
574
|
export {
|
|
575
|
+
stripAnsi,
|
|
576
|
+
segment,
|
|
577
|
+
rgbToBgAnsi,
|
|
364
578
|
rgbToAnsi,
|
|
365
579
|
resolveStyle,
|
|
366
580
|
resolveModifiersToAnsi,
|
|
581
|
+
resolveColorToRgb,
|
|
367
582
|
resolveColorToAnsi,
|
|
368
583
|
printColumns,
|
|
369
584
|
padLine,
|
|
370
585
|
mergeStyles,
|
|
371
586
|
mergeColumns,
|
|
587
|
+
line,
|
|
372
588
|
interpolateHex,
|
|
373
|
-
|
|
589
|
+
interpolateGradient,
|
|
374
590
|
hexToRgb,
|
|
375
591
|
getLineLength,
|
|
376
|
-
|
|
592
|
+
getGradientColorFromRgb,
|
|
593
|
+
getGradientBgColorFromRgb,
|
|
377
594
|
getDragon,
|
|
595
|
+
createTable,
|
|
378
596
|
createProgressBar,
|
|
379
597
|
computeMaxWidth,
|
|
380
598
|
colorToHex,
|
|
599
|
+
block,
|
|
381
600
|
Spinner,
|
|
382
601
|
SPINNERS,
|
|
383
602
|
RESET,
|
|
384
|
-
Printer
|
|
603
|
+
Printer,
|
|
604
|
+
GRADIENTS,
|
|
605
|
+
ESC
|
|
385
606
|
};
|