console-toolkit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +34 -0
  2. package/README.md +92 -0
  3. package/package.json +59 -0
  4. package/src/alphanumeric/arrows.js +31 -0
  5. package/src/alphanumeric/fractions.js +82 -0
  6. package/src/alphanumeric/number-formatters.js +131 -0
  7. package/src/alphanumeric/roman.js +86 -0
  8. package/src/alphanumeric/unicode-cultural-numbers.js +68 -0
  9. package/src/alphanumeric/unicode-letters.js +63 -0
  10. package/src/alphanumeric/unicode-numbers.js +75 -0
  11. package/src/alphanumeric/utils.js +44 -0
  12. package/src/ansi/csi.js +67 -0
  13. package/src/ansi/index.js +20 -0
  14. package/src/ansi/sgr-constants.js +99 -0
  15. package/src/ansi/sgr-state.js +398 -0
  16. package/src/ansi/sgr.js +214 -0
  17. package/src/box.js +253 -0
  18. package/src/charts/bars/block-frac-grouped.js +6 -0
  19. package/src/charts/bars/block-frac.js +36 -0
  20. package/src/charts/bars/block-grouped.js +6 -0
  21. package/src/charts/bars/block.js +43 -0
  22. package/src/charts/bars/draw-grouped.js +39 -0
  23. package/src/charts/bars/draw-stacked.js +24 -0
  24. package/src/charts/bars/frac-grouped.js +33 -0
  25. package/src/charts/bars/plain-grouped.js +6 -0
  26. package/src/charts/bars/plain.js +63 -0
  27. package/src/charts/columns/block-frac-grouped.js +6 -0
  28. package/src/charts/columns/block-frac.js +30 -0
  29. package/src/charts/columns/block-grouped.js +6 -0
  30. package/src/charts/columns/block.js +37 -0
  31. package/src/charts/columns/draw-grouped.js +48 -0
  32. package/src/charts/columns/draw-stacked.js +31 -0
  33. package/src/charts/columns/frac-grouped.js +27 -0
  34. package/src/charts/columns/plain-grouped.js +6 -0
  35. package/src/charts/columns/plain.js +39 -0
  36. package/src/charts/themes/default.js +12 -0
  37. package/src/charts/themes/rainbow-reversed.js +5 -0
  38. package/src/charts/themes/rainbow.js +8 -0
  39. package/src/charts/utils.js +75 -0
  40. package/src/draw-block-frac.js +33 -0
  41. package/src/draw-block.js +55 -0
  42. package/src/meta.js +41 -0
  43. package/src/output/show.js +40 -0
  44. package/src/output/updater.js +82 -0
  45. package/src/output/writer.js +131 -0
  46. package/src/panel.js +748 -0
  47. package/src/plot/bitmap.js +108 -0
  48. package/src/plot/draw-line.js +26 -0
  49. package/src/plot/draw-rect.js +216 -0
  50. package/src/plot/index.js +24 -0
  51. package/src/plot/to-quads.js +32 -0
  52. package/src/spinner/index.js +8 -0
  53. package/src/spinner/spin.js +51 -0
  54. package/src/spinner/spinner.js +75 -0
  55. package/src/spinner/spinners.js +65 -0
  56. package/src/strings.js +72 -0
  57. package/src/style.js +620 -0
  58. package/src/symbols.js +131 -0
  59. package/src/table/draw-borders.js +87 -0
  60. package/src/table/index.js +7 -0
  61. package/src/table/table.js +330 -0
  62. package/src/themes/blocks/unicode-half.js +9 -0
  63. package/src/themes/blocks/unicode-thin.js +9 -0
  64. package/src/themes/lines/ascii-compact.js +11 -0
  65. package/src/themes/lines/ascii-dots.js +9 -0
  66. package/src/themes/lines/ascii-girder.js +9 -0
  67. package/src/themes/lines/ascii-github.js +11 -0
  68. package/src/themes/lines/ascii-reddit.js +11 -0
  69. package/src/themes/lines/ascii-rounded.js +11 -0
  70. package/src/themes/lines/ascii.js +11 -0
  71. package/src/themes/lines/unicode-bold.js +15 -0
  72. package/src/themes/lines/unicode-rounded.js +15 -0
  73. package/src/themes/lines/unicode.js +15 -0
  74. package/src/themes/utils.js +38 -0
  75. package/src/turtle/draw-line-art.js +46 -0
  76. package/src/turtle/draw-unicode.js +33 -0
  77. package/src/turtle/index.js +12 -0
  78. package/src/turtle/turtle.js +286 -0
@@ -0,0 +1,214 @@
1
+ // SGR (Select Graphics Rendition) definitions and helpers.
2
+ // SGR is a part of CSI (Control Sequence Introducer) sequences.
3
+ // CSI is a part of Fe Escape sequences.
4
+ // Type Fe is supported by C1 control codes.
5
+ // See https://en.wikipedia.org/wiki/ANSI_escape_code for more details.
6
+
7
+ // matcher
8
+ export const matchSgr = /\x1B\[([\x30-\x3F]*)([\x20-\x2F]*)m/g;
9
+
10
+ export const Colors = {BLACK: 0, RED: 1, GREEN: 2, YELLOW: 3, BLUE: 4, MAGENTA: 5, CYAN: 6, WHITE: 7, DEFAULT: 9};
11
+
12
+ export const Commands = {
13
+ RESET_ALL: '0',
14
+ BOLD: '1',
15
+ DIM: '2',
16
+ ITALIC: '3',
17
+ UNDERLINE: '4',
18
+ BLINK: '5',
19
+ RAPID_BLINK: '6',
20
+ INVERSE: '7',
21
+ HIDDEN: '8',
22
+ STRIKETHROUGH: '9',
23
+ DEFAULT_FONT: '10',
24
+ RESET_FONT: '10',
25
+ FONT_GOTHIC: '20',
26
+ RESET_BOLD: '22',
27
+ RESET_DIM: '22',
28
+ RESET_ITALIC: '23',
29
+ RESET_UNDERLINE: '24',
30
+ RESET_BLINK: '25',
31
+ RESET_RAPID_BLINK: '25',
32
+ RESET_INVERSE: '27',
33
+ RESET_HIDDEN: '28',
34
+ RESET_STRIKETHROUGH: '29',
35
+ CURLY_UNDERLINE: '4:3',
36
+ RESET_CURLY_UNDERLINE: '24',
37
+ DOUBLE_UNDERLINE: '21',
38
+ RESET_DOUBLE_UNDERLINE: '24',
39
+ EXTENDED_COLOR: '38',
40
+ BG_EXTENDED_COLOR: '48',
41
+ DEFAULT_COLOR: '39',
42
+ BG_DEFAULT_COLOR: '49',
43
+ RESET_COLOR: '39',
44
+ RESET_BG_COLOR: '49',
45
+ OVERLINE: '53',
46
+ RESET_OVERLINE: '55',
47
+ DECORATION_COLOR: '58',
48
+ DECORATION_DEFAULT_COLOR: '59',
49
+ RESET_DECORATION_COLOR: '59'
50
+ };
51
+
52
+ export const ColorFormat = {COLOR_256: '5', TRUE_COLOR: '2'};
53
+ export const ColorFormatSize = {[ColorFormat.COLOR_256]: 3, [ColorFormat.TRUE_COLOR]: 5};
54
+
55
+ export const FgColorOptions = {
56
+ base: 30,
57
+ brightBase: 90,
58
+ default: Commands.DEFAULT_COLOR,
59
+ extended: Commands.EXTENDED_COLOR
60
+ };
61
+ export const BgColorOptions = {
62
+ base: 40,
63
+ brightBase: 100,
64
+ default: Commands.BG_DEFAULT_COLOR,
65
+ extended: Commands.BG_EXTENDED_COLOR
66
+ };
67
+ export const DecorationColorOptions = {
68
+ base: 0,
69
+ brightBase: 100,
70
+ default: Commands.RESET_DECORATION_COLOR,
71
+ extended: Commands.DECORATION_COLOR
72
+ };
73
+
74
+ const resetCommands = {};
75
+ for (const [k, v] of Object.entries(Commands)) {
76
+ if (!k.startsWith('RESET_')) continue;
77
+ const cmd = k.substring(6);
78
+ if (!Commands.hasOwnProperty(cmd)) continue;
79
+ resetCommands[Commands[cmd]] = v;
80
+ }
81
+
82
+ export const isFgColorCommand = command => (command >= '30' && command <= '37') || (command >= '90' && command <= '97');
83
+ export const isBgColorCommand = command =>
84
+ (command >= '40' && command <= '47') || (command >= '100' && command <= '107');
85
+ export const isFontCommand = command => command >= '10' && command <= '20';
86
+
87
+ export const reset = command => {
88
+ command = String(command).toUpperCase();
89
+ if (Commands.hasOwnProperty(command)) {
90
+ command = Commands[command];
91
+ }
92
+ if (resetCommands.hasOwnProperty(command)) return resetCommands[command];
93
+ if (isFgColorCommand(command)) return Commands.RESET_COLOR;
94
+ if (isBgColorCommand(command)) return Commands.RESET_BG_COLOR;
95
+ if (isFontCommand(command)) return Commands.RESET_FONT;
96
+ // return undefined in all other cases
97
+ };
98
+
99
+ export const setCommands = commands => `\x1B[${Array.isArray(commands) ? commands.join(';') : commands}m`;
100
+
101
+ export const colorNumber = color => {
102
+ if (typeof color == 'string') {
103
+ if (/^\d+$/.test(color)) {
104
+ color = parseInt(color);
105
+ } else {
106
+ color = color.toUpperCase();
107
+ return Colors.hasOwnProperty(color) ? Colors[color] : 0;
108
+ }
109
+ }
110
+ return typeof color == 'number' && color >= 0 && color <= 9 ? color : 0;
111
+ };
112
+ export const colorStdRgb = (r, g, b) => (r ? 1 : 0) + (g ? 2 : 0) + (b ? 4 : 0);
113
+
114
+ export const getColor = color => 30 + colorNumber(color);
115
+ export const getBgColor = color => 40 + colorNumber(color);
116
+ export const getBrightColor = color => 90 + colorNumber(color);
117
+ export const getBgBrightColor = color => 100 + colorNumber(color);
118
+ export const getStdRgb = (r, g, b) => getColor(colorStdRgb(r, g, b));
119
+ export const getBgStdRgb = (r, g, b) => getBgColor(colorStdRgb(r, g, b));
120
+ export const getBrightStdRgb = (r, g, b) => getBrightColor(colorStdRgb(r, g, b));
121
+ export const getBgBrightStdRgb = (r, g, b) => getBgBrightColor(colorStdRgb(r, g, b));
122
+
123
+ export const setColor = color => setCommands(getColor(color));
124
+ export const setBgColor = color => setCommands(getBgColor(color));
125
+ export const setBrightColor = color => setCommands(getBrightColor(color));
126
+ export const setBgBrightColor = color => setCommands(getBgBrightColor(color));
127
+ export const setStdRgb = (r, g, b) => setCommands(getStdRgb(r, g, b));
128
+ export const setBgStdRgb = (r, g, b) => setCommands(getBgStdRgb(r, g, b));
129
+ export const setBrightStdRgb = (r, g, b) => setCommands(getBrightStdRgb(r, g, b));
130
+ export const setBgBrightStdRgb = (r, g, b) => setCommands(getBgBrightStdRgb(r, g, b));
131
+
132
+ export const fontNumber = font => (typeof font == 'number' && font >= 0 && font <= 10 ? font : 0);
133
+
134
+ export const getFont = font => 10 + fontNumber(font);
135
+ export const setFont = font => setCommands(setFont(font));
136
+
137
+ const oneSixth = 6.0 / 256;
138
+ const oneTwentyFourth = 24.0 / 256;
139
+ const get6 = colorComponent => Math.floor(colorComponent * oneSixth);
140
+ const get24 = intensity => Math.floor(intensity * oneTwentyFourth);
141
+ const lim = (from, to) => value => Math.max(from, Math.min(to, value)); // inclusive
142
+ const lim5 = lim(0, 5);
143
+ const lim23 = lim(0, 23);
144
+
145
+ export const getRawColor256 = color => [Commands.EXTENDED_COLOR, ColorFormat.COLOR_256, color];
146
+ export const getStdColor256 = color => getRawColor256(colorNumber(color));
147
+ export const getBrightStdColor256 = color => getRawColor256(8 + colorNumber(color));
148
+ export const getColor6 = (r, g, b) => getRawColor256(16 + 36 * lim5(r) + 6 * lim5(g) + lim5(b));
149
+ export const getColor256 = (r, g, b) => getColor6(get6(r), get6(g), get6(b));
150
+ export const getHexColor256 = hex => getColor256((hex >> 16) & 0xff, (hex >> 8) & 0xff, hex & 0xff);
151
+ export const getGrayColor24 = i => getRawColor256(232 + lim23(i));
152
+ export const getGrayColor256 = i => getGrayColor24(get24(i));
153
+
154
+ export const setRawColor256 = color => setCommands(getRawColor256(color));
155
+ export const setStdColor256 = color => setCommands(getStdColor256(color));
156
+ export const setBrightStdColor256 = color => setCommands(getBrightStdColor256(color));
157
+ export const setColor6 = (r, g, b) => setCommands(getColor6(r, g, b));
158
+ export const setColor256 = (r, g, b) => setCommands(getColor256(r, g, b));
159
+ export const setHexColor256 = (r, g, b) => setCommands(getHexColor256(r, g, b));
160
+ export const setGrayColor24 = i => setCommands(getGrayColor24(i));
161
+ export const setGrayColor256 = i => setCommands(getGrayColor256(i));
162
+
163
+ export const getBgRawColor256 = color => [Commands.BG_EXTENDED_COLOR, ColorFormat.COLOR_256, color];
164
+ export const getBgStdColor256 = color => getBgStdColor256(colorNumber(color));
165
+ export const getBgBrightStdColor256 = color => getBgStdColor256(8 + colorNumber(color));
166
+ export const getBgColor6 = (r, g, b) => getBgRawColor256(16 + 36 * lim5(r) + 6 * lim5(g) + lim5(b));
167
+ export const getBgColor256 = (r, g, b) => getBgColor6(get6(r), get6(g), get6(b));
168
+ export const getBgHexColor256 = hex => getBgColor256((hex >> 16) & 0xff, (hex >> 8) & 0xff, hex & 0xff);
169
+ export const getBgGrayColor24 = i => getBgRawColor256(232 + lim23(i));
170
+ export const getBgGrayColor256 = i => getBgGrayColor24(get24(i));
171
+
172
+ export const setBgRawColor256 = color => setCommands(getBgRawColor256(color));
173
+ export const setBgStdColor256 = color => setCommands(getBgStdColor256(color));
174
+ export const setBgBrightStdColor256 = color => setCommands(getBgBrightStdColor256(color));
175
+ export const setBgColor6 = (r, g, b) => setCommands(getBgColor6(r, g, b));
176
+ export const setBgColor256 = (r, g, b) => setCommands(getBgColor256(r, g, b));
177
+ export const setBgHexColor256 = (r, g, b) => setCommands(getBgHexColor256(r, g, b));
178
+ export const setBgGrayColor24 = i => setCommands(getBgGrayColor24(i));
179
+ export const setBgGrayColor256 = i => setCommands(geBgtGrayColor256(i));
180
+
181
+ export const getTrueColor = (r, g, b) => [Commands.EXTENDED_COLOR, ColorFormat.TRUE_COLOR, r, g, b];
182
+ export const getHexTrueColor = hex => getTrueColor((hex >> 16) & 0xff, (hex >> 8) & 0xff, hex & 0xff);
183
+ export const getBgTrueColor = (r, g, b) => [Commands.BG_EXTENDED_COLOR, ColorFormat.TRUE_COLOR, r, g, b];
184
+ export const getBgHexTrueColor = hex => getBgTrueColor((hex >> 16) & 0xff, (hex >> 8) & 0xff, hex & 0xff);
185
+
186
+ export const setTrueColor = (r, g, b) => setCommands(getTrueColor(r, g, b));
187
+ export const setHexTrueColor = hex => setCommands(getHexTrueColor(hex));
188
+ export const setBgTrueColor = (r, g, b) => setCommands(getBgTrueColor(r, g, b));
189
+ export const setBgHexTrueColor = hex => setCommands(getBgHexTrueColor(hex));
190
+
191
+ export const getDecorationRawColor256 = color => [Commands.DECORATION_COLOR, ColorFormat.COLOR_256, color];
192
+ export const getDecorationStdColor256 = color => getDecorationRawColor256(colorNumber(color));
193
+ export const getDecorationBrightStdColor256 = color => getDecorationRawColor256(8 + colorNumber(color));
194
+ export const getDecorationColor6 = (r, g, b) => getDecorationRawColor256(16 + 36 * lim5(r) + 6 * lim5(g) + lim5(b));
195
+ export const getDecorationColor256 = (r, g, b) => getDecorationColor6(get6(r), get6(g), get6(b));
196
+ export const getDecorationHexColor256 = hex => getDecorationColor256((hex >> 16) & 0xff, (hex >> 8) & 0xff, hex & 0xff);
197
+ export const getDecorationGrayColor24 = i => getDecorationRawColor256(232 + lim23(i));
198
+ export const getDecorationGrayColor256 = i => getDecorationGrayColor24(get24(i));
199
+
200
+ export const setDecorationRawColor256 = color => setCommands(getDecorationRawColor256(color));
201
+ export const setDecorationStdColor256 = color => setCommands(getDecorationStdColor256(color));
202
+ export const setDecorationBrightStdColor256 = color => setCommands(getDecorationBrightStdColor256(color));
203
+ export const setDecorationColor6 = (r, g, b) => setCommands(getDecorationColor6(r, g, b));
204
+ export const setDecorationColor256 = (r, g, b) => setCommands(getDecorationColor256(r, g, b));
205
+ export const setDecorationHexColor256 = (r, g, b) => setCommands(getDecorationHexColor256(r, g, b));
206
+ export const setDecorationGrayColor24 = i => setCommands(getDecorationGrayColor24(i));
207
+ export const setDecorationGrayColor256 = i => setCommands(getDecorationGrayColor256(i));
208
+
209
+ export const getDecorationTrueColor = (r, g, b) => [Commands.DECORATION_COLOR, ColorFormat.TRUE_COLOR, r, g, b];
210
+ export const getDecorationHexTrueColor = hex =>
211
+ getDecorationTrueColor((hex >> 16) & 0xff, (hex >> 8) & 0xff, hex & 0xff);
212
+
213
+ export const setDecorationTrueColor = (r, g, b) => setCommands(getDecorationTrueColor(r, g, b));
214
+ export const setDecorationHexTrueColor = hex => setCommands(getDecorationHexTrueColor(hex));
package/src/box.js ADDED
@@ -0,0 +1,253 @@
1
+ import {addAlias} from './meta.js';
2
+ import {getLength, clipStrings, toStrings} from './strings.js';
3
+
4
+ export class Box {
5
+ constructor(s, normalized) {
6
+ if (s instanceof Box) {
7
+ this.box = [...s.box]; // copy
8
+ } else {
9
+ this.box = Array.isArray(s) && normalized ? s : Box.make(s).box;
10
+ }
11
+ }
12
+
13
+ get width() {
14
+ return this.box.length ? getLength(this.box[0]) : 0;
15
+ }
16
+ get height() {
17
+ return this.box.length;
18
+ }
19
+
20
+ static make(s, options) {
21
+ main: for (;;) {
22
+ switch (typeof s) {
23
+ case 'function':
24
+ for (let i = 0; i < 10 && typeof s == 'function'; ++i) s = s();
25
+ if (typeof s == 'function') s = String(s);
26
+ continue main;
27
+ case 'object':
28
+ if (s instanceof Box) return s.clone();
29
+ if (typeof s?.toBox == 'function') return s.toBox(options);
30
+ if (typeof s?.toPanel == 'function') return s.toPanel().toBox(options);
31
+ break;
32
+ }
33
+ s = toStrings(s);
34
+ break main;
35
+ }
36
+
37
+ if (s.length <= 1) return new Box(s, true);
38
+
39
+ const {symbol = ' ', align = 'left'} = options || {},
40
+ widths = s.map(s => getLength(s)),
41
+ width = Math.max(0, ...widths);
42
+ switch (align) {
43
+ case 'left':
44
+ case 'l':
45
+ return new Box(
46
+ s.map((s, i) => s + symbol.repeat(width - widths[i])),
47
+ true
48
+ );
49
+ case 'right':
50
+ case 'r':
51
+ return new Box(
52
+ s.map((s, i) => symbol.repeat(width - widths[i]) + s),
53
+ true
54
+ );
55
+ }
56
+ // center
57
+ return new Box(
58
+ s.map((s, i) => {
59
+ const n = width - widths[i];
60
+ if (!n) return s;
61
+ const half = n >> 1,
62
+ padding = symbol.repeat(half);
63
+ return padding + s + padding + (n & 1 ? symbol : '');
64
+ }),
65
+ true
66
+ );
67
+ }
68
+
69
+ static makeBlank(width, height, symbol = ' ') {
70
+ return new Box(height <= 0 ? [] : new Array(height).fill(symbol.repeat(width)), true);
71
+ }
72
+
73
+ toStrings() {
74
+ return this.box;
75
+ }
76
+
77
+ clone() {
78
+ return new Box(this);
79
+ }
80
+
81
+ clip(width, includeLastCommand) {
82
+ return new Box(clipStrings(this.box, width, includeLastCommand), true);
83
+ }
84
+
85
+ // padding
86
+
87
+ padLeftRight(left, right, symbol = ' ') {
88
+ const paddingSmall = symbol.repeat(Math.min(left, right)),
89
+ paddingLarge = paddingSmall + symbol.repeat(Math.max(left - right, right - left));
90
+ return new Box(
91
+ left < right
92
+ ? this.box.map(s => paddingSmall + s + paddingLarge)
93
+ : this.box.map(s => paddingLarge + s + paddingSmall),
94
+ true
95
+ );
96
+ }
97
+
98
+ padTopBottom(top, bottom, symbol = ' ') {
99
+ const padding = symbol.repeat(this.width);
100
+ return new Box([...new Array(top).fill(padding), ...this.box, ...new Array(bottom).fill(padding)], true);
101
+ }
102
+
103
+ padRight(n, symbol = ' ') {
104
+ const padding = symbol.repeat(n);
105
+ return new Box(
106
+ this.box.map(s => s + padding),
107
+ true
108
+ );
109
+ }
110
+
111
+ padLeft(n, symbol = ' ') {
112
+ const padding = symbol.repeat(n);
113
+ return new Box(
114
+ this.box.map(s => padding + s),
115
+ true
116
+ );
117
+ }
118
+
119
+ padTop(n, symbol = ' ') {
120
+ const padding = symbol.repeat(this.width);
121
+ return new Box([...new Array(n).fill(padding), ...this.box], true);
122
+ }
123
+
124
+ padBottom(n, symbol = ' ') {
125
+ const padding = symbol.repeat(this.width);
126
+ return new Box([...this.box, ...new Array(n).fill(padding)], true);
127
+ }
128
+
129
+ pad(t, r, b, l, symbol = ' ') {
130
+ // implemented the CSS padding order
131
+ if (typeof r != 'number') {
132
+ symbol = r;
133
+ r = b = l = t;
134
+ } else if (typeof b != 'number') {
135
+ symbol = b;
136
+ l = r;
137
+ b = t;
138
+ } else if (typeof l != 'number') {
139
+ symbol = l;
140
+ l = r;
141
+ }
142
+ return this.padLeftRight(l, r, symbol).padTopBottom(t, b, symbol);
143
+ }
144
+
145
+ // removing
146
+
147
+ removeRows(y, n) {
148
+ const result = [...this.box];
149
+ result.splice(y, n);
150
+ return new Box(result, true);
151
+ }
152
+
153
+ // stack
154
+
155
+ addBottom(box, {symbol = ' ', align = 'left'} = {}) {
156
+ let a = this,
157
+ b = toBox(box);
158
+ const diff = a.width - b.width;
159
+ if (diff) {
160
+ const d = Math.abs(diff);
161
+ let x = diff < 0 ? a : b;
162
+ switch (align) {
163
+ case 'left':
164
+ case 'l':
165
+ x = x.padRight(d, symbol);
166
+ break;
167
+ case 'right':
168
+ case 'r':
169
+ x = x.padLeft(d, symbol);
170
+ break;
171
+ default: // center
172
+ const half = d >> 1;
173
+ x = x.padLeftRight(half, half + (d & 1 ? 1 : 0));
174
+ break;
175
+ }
176
+ a = diff < 0 ? x : a;
177
+ b = diff < 0 ? b : x;
178
+ }
179
+ return new Box([...a.box, ...b.box], true);
180
+ }
181
+
182
+ addRight(box, {symbol = ' ', align = 'top'} = {}) {
183
+ const ah = this.height,
184
+ bh = box.height;
185
+ if (ah == bh)
186
+ return new Box(
187
+ this.box.map((s, i) => s + box.box[i]),
188
+ true
189
+ );
190
+
191
+ let t = 0,
192
+ b = 0;
193
+ const diff = Math.abs(ah - bh);
194
+ switch (align) {
195
+ case 'top':
196
+ case 't':
197
+ t = 0;
198
+ b = diff;
199
+ break;
200
+ case 'bottom':
201
+ case 'b':
202
+ t = diff;
203
+ b = 0;
204
+ break;
205
+ default: // center
206
+ const half = diff >> 1;
207
+ t = half;
208
+ b = half + (diff & 1 ? 1 : 0);
209
+ break;
210
+ }
211
+
212
+ const result = [];
213
+
214
+ if (ah < bh) {
215
+ const padding = symbol.repeat(this.width);
216
+ for (let i = 0; i < t; ++i) {
217
+ result.push(padding + box.box[i]);
218
+ }
219
+ for (let i = 0; i < ah; ++i) {
220
+ result.push(this.box[i] + box.box[i + t]);
221
+ }
222
+ for (let i = ah + t; i < bh; ++i) {
223
+ result.push(padding + box.box[i]);
224
+ }
225
+ } else {
226
+ const padding = symbol.repeat(box.width);
227
+ for (let i = 0; i < t; ++i) {
228
+ result.push(this.box[i] + padding);
229
+ }
230
+ for (let i = 0; i < bh; ++i) {
231
+ result.push(this.box[i + t] + box.box[i]);
232
+ }
233
+ for (let i = bh + t; i < ah; ++i) {
234
+ result.push(this.box[i] + padding);
235
+ }
236
+ }
237
+
238
+ return new Box(result, true);
239
+ }
240
+
241
+ // flipping
242
+
243
+ flipV() {
244
+ // return new Box(this.box.toReversed(), true);
245
+ return new Box([...this.box].reverse(), true);
246
+ }
247
+ }
248
+
249
+ addAlias(Box, 'toBox', 'clone');
250
+
251
+ export const toBox = Box.make;
252
+
253
+ export default Box;
@@ -0,0 +1,6 @@
1
+ import {drawRow} from './block-frac.js';
2
+ import drawGroupedChart from './draw-grouped.js';
3
+
4
+ export const drawChart = drawGroupedChart(drawRow);
5
+
6
+ export default drawChart;
@@ -0,0 +1,36 @@
1
+ import style from '../../style.js';
2
+ import Box from '../../box.js';
3
+ import {optimize} from '../../ansi/sgr-state.js';
4
+ import {allocateSizes, getFracSize} from '../utils.js';
5
+ import drawStackedChart from './draw-stacked.js';
6
+ import {drawRealHeightBlock} from '../../draw-block-frac.js';
7
+
8
+ // data = [datum]
9
+ // datum = {value, colorState, symbol, state}
10
+
11
+ export const drawRow = (data, width, maxValue, options = {}) => {
12
+ const {reverse, drawEmptyBorder, initState = {}} = options,
13
+ rectSize = Math.max(0, options.rectSize ?? 0.5),
14
+ sizes = allocateSizes(data, maxValue, width),
15
+ blocks = data.map((datum, i) => {
16
+ if (!datum) return Box.makeBlank(0, getFracSize(rectSize, drawEmptyBorder));
17
+ const box = drawRealHeightBlock(sizes[i], rectSize, drawEmptyBorder),
18
+ boxStyle = style.addState(initState).addState(datum.colorState).addState(datum.state);
19
+ return new Box(
20
+ box.box.map(line => boxStyle.text(line)),
21
+ true
22
+ );
23
+ }),
24
+ result = new Array(blocks[0].box.length).fill('');
25
+ if (reverse) blocks.reverse();
26
+ for (const block of blocks) {
27
+ for (let i = 0; i < block.box.length; ++i) {
28
+ result[i] += block.box[i];
29
+ }
30
+ }
31
+ return result.map(line => optimize(line));
32
+ };
33
+
34
+ export const drawChart = drawStackedChart(drawRow);
35
+
36
+ export default drawChart;
@@ -0,0 +1,6 @@
1
+ import {drawRow} from './block.js';
2
+ import drawGroupedChart from './draw-grouped.js';
3
+
4
+ export const drawChart = drawGroupedChart(drawRow);
5
+
6
+ export default drawChart;
@@ -0,0 +1,43 @@
1
+ import style from '../../style.js';
2
+ import Box from '../../box.js';
3
+ import {optimize} from '../../ansi/sgr-state.js';
4
+ import {allocateSizes} from '../utils.js';
5
+ import drawStackedChart from './draw-stacked.js';
6
+ import drawBlock from '../../draw-block.js';
7
+ import defaultBlockTheme from '../../themes/blocks/unicode-half.js';
8
+
9
+ // data = [datum]
10
+ // datum = {value, colorState, symbol, state}
11
+
12
+ export const drawRow = (data, width, maxValue, options = {}) => {
13
+ const {reverse, blockTheme = defaultBlockTheme, rectSize = 0, initState = {}} = options,
14
+ sizes = allocateSizes(data, maxValue, width),
15
+ {t = 1, b = 1, l = reverse ? 1 : 0, r = reverse ? 0 : 1} = options;
16
+
17
+ const blocks = data.map((datum, i) => {
18
+ if (!datum) return Box.makeBlank(0, Math.max(2, rectSize));
19
+ const box = drawBlock(sizes[i], Math.max(0, rectSize - 2), blockTheme, {
20
+ left: reverse ? (i + 1 < data.length ? 0 : l) : i ? 0 : l,
21
+ right: reverse ? (i ? 0 : r) : i + 1 < data.length ? 0 : r,
22
+ top: t,
23
+ bottom: b
24
+ }),
25
+ boxStyle = style.addState(initState).addState(datum.colorState).addState(datum.state);
26
+ return new Box(
27
+ box.box.map(line => boxStyle.text(line)),
28
+ true
29
+ );
30
+ }),
31
+ result = new Array(blocks[0].box.length).fill('');
32
+ if (reverse) blocks.reverse();
33
+ for (const block of blocks) {
34
+ for (let i = 0; i < block.box.length; ++i) {
35
+ result[i] += block.box[i];
36
+ }
37
+ }
38
+ return result.map(line => optimize(line));
39
+ };
40
+
41
+ export const drawChart = drawStackedChart(drawRow);
42
+
43
+ export default drawChart;
@@ -0,0 +1,39 @@
1
+ import defaultTheme from '../themes/default.js';
2
+ import {normalizeData} from '../utils.js';
3
+
4
+ export const drawChart =
5
+ drawRow =>
6
+ (values, width, options = {}) => {
7
+ const {maxValue, groupGap = 1, gap = 0, theme = defaultTheme} = options;
8
+ if (isNaN(width) || width <= 0) throw new Error(`"width" should be a positive integer instead of "${width}"`);
9
+
10
+ const data = normalizeData(values, theme),
11
+ maxSeriesLength = Math.max(0, ...data.map(series => series.length));
12
+
13
+ // normalize length of series and flatten the result
14
+ const newData = [];
15
+ data.forEach(series => {
16
+ newData.push(...series);
17
+ if (series.length < maxSeriesLength) newData.push(...new Array(maxSeriesLength - series.length).fill(null));
18
+ });
19
+
20
+ const max =
21
+ typeof maxValue == 'number' && maxValue >= 0 ? maxValue : Math.max(0, ...newData.map(datum => datum?.value || 0));
22
+
23
+ if (gap < 1 && groupGap < 1) return newData.map(datum => drawRow([datum], width, max, options));
24
+
25
+ const result = [];
26
+ newData.forEach((datum, i) => {
27
+ if (i) {
28
+ if (i % maxSeriesLength == 0) {
29
+ if (groupGap > 0) result.push(new Array(groupGap).fill(''));
30
+ } else {
31
+ if (gap > 0) result.push(new Array(gap).fill(''));
32
+ }
33
+ }
34
+ result.push(drawRow([datum], width, max, options));
35
+ });
36
+ return result.flat(1);
37
+ };
38
+
39
+ export default drawChart;
@@ -0,0 +1,24 @@
1
+ import defaultTheme from '../themes/default.js';
2
+ import {normalizeData, sumValues} from '../utils.js';
3
+
4
+ export const drawChart =
5
+ drawRow =>
6
+ (values, width, options = {}) => {
7
+ const {maxValue, gap = 0, theme = defaultTheme} = options;
8
+ if (isNaN(width) || width <= 0) throw new Error(`"width" should be a positive integer instead of "${width}"`);
9
+
10
+ const data = normalizeData(values, theme),
11
+ max =
12
+ typeof maxValue == 'number' ? (maxValue < 0 ? -1 : maxValue) : Math.max(0, ...data.map(row => sumValues(row)));
13
+
14
+ if (gap < 1) return data.map(row => drawRow(row, width, max, options)).flat(1);
15
+
16
+ const result = [];
17
+ data.forEach((row, i) => {
18
+ if (i) result.push(...new Array(gap).fill(''));
19
+ result.push(drawRow(row, width, max, options));
20
+ });
21
+ return result.flat(1);
22
+ };
23
+
24
+ export default drawChart;
@@ -0,0 +1,33 @@
1
+ import style from '../../style.js';
2
+ import Box from '../../box.js';
3
+ import {optimize} from '../../ansi/sgr-state.js';
4
+ import {drawRealWidthBlock} from '../../draw-block-frac.js';
5
+ import drawGroupedChart from './draw-grouped.js';
6
+
7
+ // data = [datum]
8
+ // datum = {value, colorState, symbol, state}
9
+
10
+ export const drawRow = (data, width, maxValue, options = {}) => {
11
+ const {reverse, rectSize = 1, initState = {}} = options,
12
+ blocks = data.map(datum => {
13
+ if (!datum) return Box.makeBlank(0, rectSize);
14
+ const box = drawRealWidthBlock((datum.value / maxValue) * width, rectSize),
15
+ boxStyle = style.addState(initState).addState(datum.colorState).addState(datum.state);
16
+ return new Box(
17
+ box.box.map(line => boxStyle.text(line)),
18
+ true
19
+ );
20
+ }),
21
+ result = new Array(blocks[0].box.length).fill('');
22
+ if (reverse) blocks.reverse();
23
+ for (const block of blocks) {
24
+ for (let i = 0; i < block.box.length; ++i) {
25
+ result[i] += block.box[i];
26
+ }
27
+ }
28
+ return result.map(line => optimize(line));
29
+ };
30
+
31
+ export const drawChart = drawGroupedChart(drawRow);
32
+
33
+ export default drawChart;
@@ -0,0 +1,6 @@
1
+ import {drawRow} from './plain.js';
2
+ import drawGroupedChart from './draw-grouped.js';
3
+
4
+ export const drawChart = drawGroupedChart(drawRow);
5
+
6
+ export default drawChart;