@flyingrobots/bijou 4.4.1 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -1
- package/dist/adapters/test/index.d.ts.map +1 -1
- package/dist/adapters/test/index.js +1 -3
- package/dist/adapters/test/index.js.map +1 -1
- package/dist/adapters/test/runtime.d.ts.map +1 -1
- package/dist/adapters/test/runtime.js +4 -3
- package/dist/adapters/test/runtime.js.map +1 -1
- package/dist/context-theme.d.ts +25 -0
- package/dist/context-theme.d.ts.map +1 -1
- package/dist/context-theme.js +19 -0
- package/dist/context-theme.js.map +1 -1
- package/dist/context.d.ts +13 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +24 -3
- package/dist/context.js.map +1 -1
- package/dist/core/active-binding-collection.d.ts +49 -0
- package/dist/core/active-binding-collection.d.ts.map +1 -0
- package/dist/core/active-binding-collection.js +264 -0
- package/dist/core/active-binding-collection.js.map +1 -0
- package/dist/core/app-shell-composition.d.ts +44 -0
- package/dist/core/app-shell-composition.d.ts.map +1 -0
- package/dist/core/app-shell-composition.js +123 -0
- package/dist/core/app-shell-composition.js.map +1 -0
- package/dist/core/binding-frame-update.d.ts +18 -0
- package/dist/core/binding-frame-update.d.ts.map +1 -0
- package/dist/core/binding-frame-update.js +133 -0
- package/dist/core/binding-frame-update.js.map +1 -0
- package/dist/core/binding-lifecycle.d.ts +65 -0
- package/dist/core/binding-lifecycle.d.ts.map +1 -0
- package/dist/core/binding-lifecycle.js +357 -0
- package/dist/core/binding-lifecycle.js.map +1 -0
- package/dist/core/binding.d.ts +192 -0
- package/dist/core/binding.d.ts.map +1 -0
- package/dist/core/binding.js +587 -0
- package/dist/core/binding.js.map +1 -0
- package/dist/core/block-metadata.d.ts +113 -0
- package/dist/core/block-metadata.d.ts.map +1 -0
- package/dist/core/block-metadata.js +376 -0
- package/dist/core/block-metadata.js.map +1 -0
- package/dist/core/block-tree-render.d.ts +17 -0
- package/dist/core/block-tree-render.d.ts.map +1 -0
- package/dist/core/block-tree-render.js +186 -0
- package/dist/core/block-tree-render.js.map +1 -0
- package/dist/core/component-metadata.d.ts +63 -0
- package/dist/core/component-metadata.d.ts.map +1 -0
- package/dist/core/component-metadata.js +158 -0
- package/dist/core/component-metadata.js.map +1 -0
- package/dist/core/components/alert-v3.d.ts.map +1 -1
- package/dist/core/components/alert-v3.js +5 -4
- package/dist/core/components/alert-v3.js.map +1 -1
- package/dist/core/components/alert.d.ts.map +1 -1
- package/dist/core/components/alert.js +7 -8
- package/dist/core/components/alert.js.map +1 -1
- package/dist/core/components/badge.d.ts.map +1 -1
- package/dist/core/components/badge.js +19 -18
- package/dist/core/components/badge.js.map +1 -1
- package/dist/core/components/box-v3.d.ts.map +1 -1
- package/dist/core/components/box-v3.js +29 -29
- package/dist/core/components/box-v3.js.map +1 -1
- package/dist/core/components/dag-edges.d.ts +28 -5
- package/dist/core/components/dag-edges.d.ts.map +1 -1
- package/dist/core/components/dag-edges.js +116 -22
- package/dist/core/components/dag-edges.js.map +1 -1
- package/dist/core/components/dag-layout.d.ts +3 -4
- package/dist/core/components/dag-layout.d.ts.map +1 -1
- package/dist/core/components/dag-layout.js +42 -9
- package/dist/core/components/dag-layout.js.map +1 -1
- package/dist/core/components/dag-render.d.ts +4 -3
- package/dist/core/components/dag-render.d.ts.map +1 -1
- package/dist/core/components/dag-render.js +209 -105
- package/dist/core/components/dag-render.js.map +1 -1
- package/dist/core/components/dag-source.d.ts +4 -0
- package/dist/core/components/dag-source.d.ts.map +1 -1
- package/dist/core/components/dag-source.js +10 -0
- package/dist/core/components/dag-source.js.map +1 -1
- package/dist/core/components/dag.d.ts +20 -4
- package/dist/core/components/dag.d.ts.map +1 -1
- package/dist/core/components/dag.js.map +1 -1
- package/dist/core/components/explainability.d.ts.map +1 -1
- package/dist/core/components/explainability.js +30 -87
- package/dist/core/components/explainability.js.map +1 -1
- package/dist/core/components/guided-flow.d.ts +32 -0
- package/dist/core/components/guided-flow.d.ts.map +1 -0
- package/dist/core/components/guided-flow.js +131 -0
- package/dist/core/components/guided-flow.js.map +1 -0
- package/dist/core/components/hyperlink.d.ts.map +1 -1
- package/dist/core/components/hyperlink.js +7 -4
- package/dist/core/components/hyperlink.js.map +1 -1
- package/dist/core/components/index.d.ts +5 -3
- package/dist/core/components/index.d.ts.map +1 -1
- package/dist/core/components/index.js +1 -0
- package/dist/core/components/index.js.map +1 -1
- package/dist/core/components/markdown-parse.d.ts +4 -0
- package/dist/core/components/markdown-parse.d.ts.map +1 -1
- package/dist/core/components/markdown-parse.js +66 -2
- package/dist/core/components/markdown-parse.js.map +1 -1
- package/dist/core/components/markdown-render.d.ts.map +1 -1
- package/dist/core/components/markdown-render.js +220 -14
- package/dist/core/components/markdown-render.js.map +1 -1
- package/dist/core/components/markdown.d.ts +4 -3
- package/dist/core/components/markdown.d.ts.map +1 -1
- package/dist/core/components/markdown.js +6 -5
- package/dist/core/components/markdown.js.map +1 -1
- package/dist/core/components/paginator.d.ts.map +1 -1
- package/dist/core/components/paginator.js +5 -3
- package/dist/core/components/paginator.js.map +1 -1
- package/dist/core/components/perf-overlay.d.ts.map +1 -1
- package/dist/core/components/perf-overlay.js +3 -2
- package/dist/core/components/perf-overlay.js.map +1 -1
- package/dist/core/components/preference-list.d.ts.map +1 -1
- package/dist/core/components/preference-list.js +75 -37
- package/dist/core/components/preference-list.js.map +1 -1
- package/dist/core/components/progress.d.ts.map +1 -1
- package/dist/core/components/progress.js +4 -3
- package/dist/core/components/progress.js.map +1 -1
- package/dist/core/components/separator-v3.d.ts.map +1 -1
- package/dist/core/components/separator-v3.js +11 -11
- package/dist/core/components/separator-v3.js.map +1 -1
- package/dist/core/components/separator.d.ts.map +1 -1
- package/dist/core/components/separator.js +4 -1
- package/dist/core/components/separator.js.map +1 -1
- package/dist/core/components/skeleton.d.ts.map +1 -1
- package/dist/core/components/skeleton.js +3 -2
- package/dist/core/components/skeleton.js.map +1 -1
- package/dist/core/components/surface-text.d.ts +7 -0
- package/dist/core/components/surface-text.d.ts.map +1 -1
- package/dist/core/components/surface-text.js +33 -25
- package/dist/core/components/surface-text.js.map +1 -1
- package/dist/core/components/table-v3.d.ts +5 -2
- package/dist/core/components/table-v3.d.ts.map +1 -1
- package/dist/core/components/table-v3.js +162 -37
- package/dist/core/components/table-v3.js.map +1 -1
- package/dist/core/components/table.d.ts +51 -7
- package/dist/core/components/table.d.ts.map +1 -1
- package/dist/core/components/table.js +655 -81
- package/dist/core/components/table.js.map +1 -1
- package/dist/core/fixture-promotion.d.ts +33 -0
- package/dist/core/fixture-promotion.d.ts.map +1 -0
- package/dist/core/fixture-promotion.js +62 -0
- package/dist/core/fixture-promotion.js.map +1 -0
- package/dist/core/forms/filter-interactive.d.ts.map +1 -1
- package/dist/core/forms/filter-interactive.js +2 -4
- package/dist/core/forms/filter-interactive.js.map +1 -1
- package/dist/core/forms/multiselect.d.ts.map +1 -1
- package/dist/core/forms/multiselect.js +2 -4
- package/dist/core/forms/multiselect.js.map +1 -1
- package/dist/core/forms/note.d.ts.map +1 -1
- package/dist/core/forms/note.js +2 -1
- package/dist/core/forms/note.js.map +1 -1
- package/dist/core/forms/select.d.ts.map +1 -1
- package/dist/core/forms/select.js +2 -4
- package/dist/core/forms/select.js.map +1 -1
- package/dist/core/forms/textarea-editor.d.ts.map +1 -1
- package/dist/core/forms/textarea-editor.js +7 -5
- package/dist/core/forms/textarea-editor.js.map +1 -1
- package/dist/core/layout/envelope.d.ts +174 -0
- package/dist/core/layout/envelope.d.ts.map +1 -0
- package/dist/core/layout/envelope.js +336 -0
- package/dist/core/layout/envelope.js.map +1 -0
- package/dist/core/layout/geometry.d.ts +39 -0
- package/dist/core/layout/geometry.d.ts.map +1 -0
- package/dist/core/layout/geometry.js +201 -0
- package/dist/core/layout/geometry.js.map +1 -0
- package/dist/core/mode-lowering.d.ts +48 -0
- package/dist/core/mode-lowering.d.ts.map +1 -0
- package/dist/core/mode-lowering.js +176 -0
- package/dist/core/mode-lowering.js.map +1 -0
- package/dist/core/numeric.d.ts +16 -0
- package/dist/core/numeric.d.ts.map +1 -0
- package/dist/core/numeric.js +37 -0
- package/dist/core/numeric.js.map +1 -0
- package/dist/core/render/differ.d.ts.map +1 -1
- package/dist/core/render/differ.js +15 -13
- package/dist/core/render/differ.js.map +1 -1
- package/dist/core/runtime-viewport.d.ts.map +1 -1
- package/dist/core/runtime-viewport.js +2 -3
- package/dist/core/runtime-viewport.js.map +1 -1
- package/dist/core/schema-block.d.ts +63 -0
- package/dist/core/schema-block.d.ts.map +1 -0
- package/dist/core/schema-block.js +361 -0
- package/dist/core/schema-block.js.map +1 -0
- package/dist/core/selection.d.ts +127 -0
- package/dist/core/selection.d.ts.map +1 -0
- package/dist/core/selection.js +350 -0
- package/dist/core/selection.js.map +1 -0
- package/dist/core/standard-blocks.d.ts +264 -0
- package/dist/core/standard-blocks.d.ts.map +1 -0
- package/dist/core/standard-blocks.js +2518 -0
- package/dist/core/standard-blocks.js.map +1 -0
- package/dist/core/story-capture.d.ts +48 -0
- package/dist/core/story-capture.d.ts.map +1 -0
- package/dist/core/story-capture.js +64 -0
- package/dist/core/story-capture.js.map +1 -0
- package/dist/core/text/grapheme.d.ts +51 -0
- package/dist/core/text/grapheme.d.ts.map +1 -1
- package/dist/core/text/grapheme.js +68 -0
- package/dist/core/text/grapheme.js.map +1 -1
- package/dist/core/text/icon-presentation.d.ts +10 -0
- package/dist/core/text/icon-presentation.d.ts.map +1 -0
- package/dist/core/text/icon-presentation.js +12 -0
- package/dist/core/text/icon-presentation.js.map +1 -0
- package/dist/core/text/index.d.ts +2 -1
- package/dist/core/text/index.d.ts.map +1 -1
- package/dist/core/text/index.js +2 -1
- package/dist/core/text/index.js.map +1 -1
- package/dist/core/text/wrap.d.ts.map +1 -1
- package/dist/core/text/wrap.js +37 -20
- package/dist/core/text/wrap.js.map +1 -1
- package/dist/core/theme/color.d.ts +32 -0
- package/dist/core/theme/color.d.ts.map +1 -1
- package/dist/core/theme/color.js +68 -0
- package/dist/core/theme/color.js.map +1 -1
- package/dist/core/theme/doctor.d.ts +37 -0
- package/dist/core/theme/doctor.d.ts.map +1 -0
- package/dist/core/theme/doctor.js +175 -0
- package/dist/core/theme/doctor.js.map +1 -0
- package/dist/core/theme/dtcg.d.ts.map +1 -1
- package/dist/core/theme/dtcg.js +10 -1
- package/dist/core/theme/dtcg.js.map +1 -1
- package/dist/core/theme/graph-types.d.ts +5 -0
- package/dist/core/theme/graph-types.d.ts.map +1 -1
- package/dist/core/theme/graph.d.ts.map +1 -1
- package/dist/core/theme/graph.js +52 -5
- package/dist/core/theme/graph.js.map +1 -1
- package/dist/core/theme/index.d.ts +4 -1
- package/dist/core/theme/index.d.ts.map +1 -1
- package/dist/core/theme/index.js +3 -1
- package/dist/core/theme/index.js.map +1 -1
- package/dist/core/theme/presets.d.ts +3 -2
- package/dist/core/theme/presets.d.ts.map +1 -1
- package/dist/core/theme/presets.js +22 -29
- package/dist/core/theme/presets.js.map +1 -1
- package/dist/core/theme/tokens.d.ts +1 -1
- package/dist/core/theme/tokens.d.ts.map +1 -1
- package/dist/factory.d.ts +3 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +4 -6
- package/dist/factory.js.map +1 -1
- package/dist/index.d.ts +23 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/dist/ports/context.d.ts +6 -1
- package/dist/ports/context.d.ts.map +1 -1
- package/dist/ports/surface.d.ts +6 -4
- package/dist/ports/surface.d.ts.map +1 -1
- package/dist/ports/surface.js +40 -23
- package/dist/ports/surface.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { RESET_SGR } from '../ansi.js';
|
|
2
|
+
import { ANSI_OSC8_RE, ANSI_SGR_RE, graphemeClusterWidth, segmentGraphemes, stripAnsi, } from '../text/grapheme.js';
|
|
3
3
|
import { wrapToWidth } from '../text/wrap.js';
|
|
4
4
|
import { resolveCtx } from '../resolve-ctx.js';
|
|
5
5
|
import { renderByMode } from '../mode-render.js';
|
|
6
6
|
import { makeBgFill } from '../bg-fill.js';
|
|
7
|
+
import { sanitizeNonNegativeInt, sanitizeOptionalNonNegativeInt, sanitizeOptionalPositiveInt, sanitizePositiveInt, } from '../numeric.js';
|
|
7
8
|
import { resolveOverflowBehavior } from './overflow.js';
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
+
* Structural width added by the interactive table frame for a given column count.
|
|
11
|
+
*
|
|
12
|
+
* Each column contributes two padding spaces and one vertical divider, with one
|
|
13
|
+
* extra border character for the outer edge.
|
|
14
|
+
*/
|
|
15
|
+
export function interactiveTableBorderOverhead(columnCount) {
|
|
16
|
+
return Math.max(0, columnCount) * 3 + 1;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Total rendered width of an interactive table for the supplied column widths.
|
|
20
|
+
*/
|
|
21
|
+
export function measureInteractiveTableWidth(columnWidths) {
|
|
22
|
+
return columnWidths.reduce((total, width) => total + width, 0)
|
|
23
|
+
+ interactiveTableBorderOverhead(columnWidths.length);
|
|
24
|
+
}
|
|
25
|
+
function isTableOptions(value) {
|
|
26
|
+
return !Array.isArray(value);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Calculate the visible (non-ANSI) display width of a string.
|
|
10
30
|
*
|
|
11
31
|
* @param str - Input string potentially containing ANSI codes.
|
|
12
|
-
* @returns The number of visible
|
|
32
|
+
* @returns The number of visible terminal columns.
|
|
13
33
|
*/
|
|
14
34
|
function visibleLength(str) {
|
|
15
|
-
|
|
35
|
+
let width = 0;
|
|
36
|
+
for (const grapheme of segmentGraphemes(stripAnsi(str))) {
|
|
37
|
+
width += tableGraphemeWidth(grapheme);
|
|
38
|
+
}
|
|
39
|
+
return width;
|
|
16
40
|
}
|
|
17
41
|
/**
|
|
18
42
|
* Right-pad a string to a target width, accounting for ANSI escape sequences.
|
|
@@ -25,96 +49,646 @@ function padRight(str, width) {
|
|
|
25
49
|
const visible = visibleLength(str);
|
|
26
50
|
return visible >= width ? str : str + ' '.repeat(width - visible);
|
|
27
51
|
}
|
|
52
|
+
function padLeft(str, width) {
|
|
53
|
+
const visible = visibleLength(str);
|
|
54
|
+
return visible >= width ? str : ' '.repeat(width - visible) + str;
|
|
55
|
+
}
|
|
56
|
+
function padCenter(str, width) {
|
|
57
|
+
const visible = visibleLength(str);
|
|
58
|
+
if (visible >= width)
|
|
59
|
+
return str;
|
|
60
|
+
const remaining = width - visible;
|
|
61
|
+
const left = Math.floor(remaining / 2);
|
|
62
|
+
return ' '.repeat(left) + str + ' '.repeat(remaining - left);
|
|
63
|
+
}
|
|
64
|
+
function alignCell(str, width, align) {
|
|
65
|
+
if (align === 'right')
|
|
66
|
+
return padLeft(str, width);
|
|
67
|
+
if (align === 'center')
|
|
68
|
+
return padCenter(str, width);
|
|
69
|
+
return padRight(str, width);
|
|
70
|
+
}
|
|
28
71
|
function normalizeColumnWidth(width) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
72
|
+
return sanitizeOptionalNonNegativeInt(width);
|
|
73
|
+
}
|
|
74
|
+
function normalizePositiveWeight(weight) {
|
|
75
|
+
if (weight == null || !Number.isFinite(weight))
|
|
76
|
+
return 1;
|
|
77
|
+
return Math.max(0, Math.floor(weight));
|
|
78
|
+
}
|
|
79
|
+
function maxVisibleLineWidth(value) {
|
|
80
|
+
const lines = String(value ?? '').split('\n');
|
|
81
|
+
return lines.reduce((max, line) => Math.max(max, visibleLength(line)), 0);
|
|
82
|
+
}
|
|
83
|
+
function normalizeRows(rows) {
|
|
84
|
+
return (rows ?? []).map(row => (row ?? []).map(cell => String(cell ?? '')));
|
|
85
|
+
}
|
|
86
|
+
function resolveColumns(suppliedColumns, rows, variant) {
|
|
87
|
+
const columns = suppliedColumns ?? [];
|
|
88
|
+
if (columns.length > 0)
|
|
89
|
+
return [...columns];
|
|
90
|
+
if (variant === 'definition') {
|
|
91
|
+
return [
|
|
92
|
+
{ header: 'Field', minWidth: 5 },
|
|
93
|
+
{ header: 'Value', minWidth: 5, weight: 3 },
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
const inferredCount = rows.reduce((max, row) => Math.max(max, row.length), 0);
|
|
97
|
+
return Array.from({ length: inferredCount }, () => ({ header: '' }));
|
|
98
|
+
}
|
|
99
|
+
function normalizeTable(options) {
|
|
100
|
+
const rows = normalizeRows(options.rows);
|
|
101
|
+
const variant = options.variant ?? 'box';
|
|
102
|
+
const columns = resolveColumns(options.columns, rows, variant);
|
|
103
|
+
return {
|
|
104
|
+
columns,
|
|
105
|
+
rows,
|
|
106
|
+
showHeader: variant === 'definition' || columns.some(column => (column.header ?? '').length > 0),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function structuralOverhead(variant, columnCount, columnGap) {
|
|
110
|
+
if (columnCount <= 0)
|
|
111
|
+
return variant === 'box' || variant === 'ascii-grid' ? 2 : 0;
|
|
112
|
+
if (variant === 'box' || variant === 'ascii-grid') {
|
|
113
|
+
return interactiveTableBorderOverhead(columnCount);
|
|
114
|
+
}
|
|
115
|
+
if (variant === 'markdown') {
|
|
116
|
+
return columnCount * 3 + 1;
|
|
117
|
+
}
|
|
118
|
+
return Math.max(0, columnCount - 1) * columnGap;
|
|
119
|
+
}
|
|
120
|
+
function resolveTargetWidth(options, ctx, layout) {
|
|
121
|
+
const explicitWidth = sanitizeOptionalPositiveInt(options.width);
|
|
122
|
+
if (explicitWidth !== undefined)
|
|
123
|
+
return explicitWidth;
|
|
124
|
+
const explicitMaxWidth = sanitizeOptionalPositiveInt(options.maxWidth);
|
|
125
|
+
if (layout === 'intrinsic')
|
|
126
|
+
return explicitMaxWidth;
|
|
127
|
+
const runtimeWidth = sanitizePositiveInt(ctx.runtime.columns, 80);
|
|
128
|
+
return explicitMaxWidth === undefined ? runtimeWidth : Math.min(runtimeWidth, explicitMaxWidth);
|
|
34
129
|
}
|
|
35
|
-
function
|
|
130
|
+
function columnPreferredWidth(column, rows, columnIndex) {
|
|
131
|
+
const fixedWidth = normalizeColumnWidth(column.width);
|
|
132
|
+
if (fixedWidth !== undefined)
|
|
133
|
+
return fixedWidth;
|
|
134
|
+
let preferred = Math.max(1, maxVisibleLineWidth(column.header ?? ''));
|
|
135
|
+
for (const row of rows) {
|
|
136
|
+
preferred = Math.max(preferred, maxVisibleLineWidth(row[columnIndex] ?? ''));
|
|
137
|
+
}
|
|
138
|
+
const maxWidth = sanitizeOptionalNonNegativeInt(column.maxWidth);
|
|
139
|
+
if (maxWidth !== undefined)
|
|
140
|
+
preferred = Math.min(preferred, maxWidth);
|
|
141
|
+
const minWidth = sanitizeOptionalNonNegativeInt(column.minWidth);
|
|
142
|
+
if (minWidth !== undefined)
|
|
143
|
+
preferred = Math.max(preferred, Math.min(minWidth, maxWidth ?? minWidth));
|
|
144
|
+
return preferred;
|
|
145
|
+
}
|
|
146
|
+
function columnMinWidth(column, preferredWidth) {
|
|
147
|
+
const fixedWidth = normalizeColumnWidth(column.width);
|
|
148
|
+
if (fixedWidth !== undefined)
|
|
149
|
+
return fixedWidth;
|
|
150
|
+
const maxWidth = sanitizeOptionalNonNegativeInt(column.maxWidth);
|
|
151
|
+
const rawMinWidth = sanitizeOptionalNonNegativeInt(column.minWidth) ?? Math.min(1, preferredWidth);
|
|
152
|
+
const constrainedMin = Math.min(rawMinWidth, maxWidth ?? rawMinWidth);
|
|
153
|
+
return Math.min(preferredWidth, constrainedMin);
|
|
154
|
+
}
|
|
155
|
+
function fitColumnWidths(columns, rows, variant, layout, targetWidth, columnGap) {
|
|
156
|
+
const preferred = columns.map((column, index) => columnPreferredWidth(column, rows, index));
|
|
157
|
+
if (layout === 'intrinsic' && targetWidth === undefined)
|
|
158
|
+
return preferred;
|
|
159
|
+
const contentTarget = targetWidth === undefined
|
|
160
|
+
? undefined
|
|
161
|
+
: Math.max(0, targetWidth - structuralOverhead(variant, columns.length, columnGap));
|
|
162
|
+
if (contentTarget === undefined)
|
|
163
|
+
return preferred;
|
|
164
|
+
const preferredTotal = preferred.reduce((sum, width) => sum + width, 0);
|
|
165
|
+
if (preferredTotal <= contentTarget)
|
|
166
|
+
return preferred;
|
|
167
|
+
const minimum = columns.map((column, index) => columnMinWidth(column, preferred[index]));
|
|
168
|
+
const minimumTotal = minimum.reduce((sum, width) => sum + width, 0);
|
|
169
|
+
if (minimumTotal >= contentTarget)
|
|
170
|
+
return minimum;
|
|
171
|
+
const widths = [...minimum];
|
|
172
|
+
const remainingCapacity = preferred.map((width, index) => Math.max(0, width - minimum[index]));
|
|
173
|
+
let remainingBudget = contentTarget - minimumTotal;
|
|
174
|
+
while (remainingBudget > 0) {
|
|
175
|
+
const active = remainingCapacity
|
|
176
|
+
.map((capacity, index) => ({ capacity, index }))
|
|
177
|
+
.filter(entry => entry.capacity > 0);
|
|
178
|
+
if (active.length === 0)
|
|
179
|
+
break;
|
|
180
|
+
const totalWeight = active.reduce((sum, entry) => {
|
|
181
|
+
return sum + Math.max(1, normalizePositiveWeight(columns[entry.index]?.weight));
|
|
182
|
+
}, 0);
|
|
183
|
+
let used = 0;
|
|
184
|
+
const remainders = [];
|
|
185
|
+
for (const entry of active) {
|
|
186
|
+
const weight = Math.max(1, normalizePositiveWeight(columns[entry.index]?.weight));
|
|
187
|
+
const exact = (remainingBudget * weight) / totalWeight;
|
|
188
|
+
const add = Math.min(entry.capacity, Math.floor(exact));
|
|
189
|
+
if (add > 0) {
|
|
190
|
+
widths[entry.index] += add;
|
|
191
|
+
remainingCapacity[entry.index] -= add;
|
|
192
|
+
used += add;
|
|
193
|
+
}
|
|
194
|
+
remainders.push({
|
|
195
|
+
index: entry.index,
|
|
196
|
+
remainder: exact - Math.floor(exact),
|
|
197
|
+
capacity: remainingCapacity[entry.index],
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (used === 0) {
|
|
201
|
+
const sortedRemainders = remainders
|
|
202
|
+
.filter(entry => entry.capacity > 0)
|
|
203
|
+
.sort((left, right) => {
|
|
204
|
+
if (right.remainder !== left.remainder)
|
|
205
|
+
return right.remainder - left.remainder;
|
|
206
|
+
return remainingCapacity[right.index] - remainingCapacity[left.index];
|
|
207
|
+
});
|
|
208
|
+
const next = sortedRemainders[0];
|
|
209
|
+
if (!next)
|
|
210
|
+
break;
|
|
211
|
+
widths[next.index]++;
|
|
212
|
+
remainingCapacity[next.index]--;
|
|
213
|
+
used = 1;
|
|
214
|
+
}
|
|
215
|
+
remainingBudget -= used;
|
|
216
|
+
}
|
|
217
|
+
return widths;
|
|
218
|
+
}
|
|
219
|
+
function formatCellLines(value, width, overflow, wrapMode) {
|
|
36
220
|
const safeValue = value ?? '';
|
|
37
|
-
if (!fixedWidth)
|
|
38
|
-
return safeValue.split('\n');
|
|
39
221
|
if (overflow === 'truncate') {
|
|
40
|
-
return safeValue.split('\n').map(
|
|
222
|
+
return safeValue.split('\n').map(line => clipCellToWidth(line, width));
|
|
41
223
|
}
|
|
42
|
-
|
|
224
|
+
if (wrapMode === 'word')
|
|
225
|
+
return wrapToWidth(safeValue, width);
|
|
226
|
+
return safeValue.split('\n').flatMap(line => wrapCellToWidth(line, width));
|
|
43
227
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
228
|
+
const TABLE_EMOJI_PRESENTATION_RE = /\p{Emoji_Presentation}/u;
|
|
229
|
+
function tableGraphemeWidth(grapheme) {
|
|
230
|
+
if (TABLE_EMOJI_PRESENTATION_RE.test(grapheme))
|
|
231
|
+
return 2;
|
|
232
|
+
return graphemeClusterWidth(grapheme);
|
|
233
|
+
}
|
|
234
|
+
function isOsc8Escape(raw) {
|
|
235
|
+
return raw.startsWith('\x1b]8;;');
|
|
236
|
+
}
|
|
237
|
+
const OSC8_CLOSE = '\x1b]8;;\x1b\\';
|
|
238
|
+
const OSC8_CLOSE_BEL = '\x1b]8;;\x07';
|
|
239
|
+
function isOsc8Close(raw) {
|
|
240
|
+
return raw === OSC8_CLOSE || raw === OSC8_CLOSE_BEL;
|
|
241
|
+
}
|
|
242
|
+
function isResetEscape(raw) {
|
|
243
|
+
return raw === RESET_SGR;
|
|
244
|
+
}
|
|
245
|
+
function tokenizeTableText(str) {
|
|
246
|
+
const regex = new RegExp(`${ANSI_SGR_RE.source}|${ANSI_OSC8_RE.source}`, 'g');
|
|
247
|
+
const tokens = [];
|
|
248
|
+
let lastIndex = 0;
|
|
249
|
+
for (const match of str.matchAll(regex)) {
|
|
250
|
+
const index = match.index ?? 0;
|
|
251
|
+
if (index > lastIndex) {
|
|
252
|
+
const raw = str.slice(lastIndex, index);
|
|
253
|
+
for (const grapheme of segmentGraphemes(raw)) {
|
|
254
|
+
tokens.push({
|
|
255
|
+
kind: 'grapheme',
|
|
256
|
+
raw: grapheme,
|
|
257
|
+
width: tableGraphemeWidth(grapheme),
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
tokens.push({ kind: 'ansi', raw: match[0] });
|
|
262
|
+
lastIndex = index + match[0].length;
|
|
263
|
+
}
|
|
264
|
+
if (lastIndex < str.length) {
|
|
265
|
+
const raw = str.slice(lastIndex);
|
|
266
|
+
for (const grapheme of segmentGraphemes(raw)) {
|
|
267
|
+
tokens.push({
|
|
268
|
+
kind: 'grapheme',
|
|
269
|
+
raw: grapheme,
|
|
270
|
+
width: tableGraphemeWidth(grapheme),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return tokens;
|
|
275
|
+
}
|
|
276
|
+
function activeTableAnsiPrefix(activeOsc8, activeStyle) {
|
|
277
|
+
return activeOsc8 + activeStyle;
|
|
278
|
+
}
|
|
279
|
+
function finalizeTableWrappedLine(raw, activeOsc8, activeStyle) {
|
|
280
|
+
let result = raw;
|
|
281
|
+
if (activeOsc8.length > 0 && !result.endsWith(OSC8_CLOSE) && !result.endsWith(OSC8_CLOSE_BEL)) {
|
|
282
|
+
result += OSC8_CLOSE;
|
|
283
|
+
}
|
|
284
|
+
if (activeStyle.length > 0 && !result.endsWith(RESET_SGR)) {
|
|
285
|
+
result += RESET_SGR;
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
function clipCellToWidth(str, maxWidth) {
|
|
290
|
+
if (maxWidth <= 0)
|
|
291
|
+
return '';
|
|
292
|
+
const tokens = tokenizeTableText(str);
|
|
293
|
+
let visible = 0;
|
|
294
|
+
let result = '';
|
|
295
|
+
let hasStyle = false;
|
|
296
|
+
let activeOsc8 = '';
|
|
297
|
+
for (const token of tokens) {
|
|
298
|
+
if (token.kind === 'ansi') {
|
|
299
|
+
result += token.raw;
|
|
300
|
+
if (isOsc8Escape(token.raw)) {
|
|
301
|
+
activeOsc8 = isOsc8Close(token.raw) ? '' : token.raw;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
hasStyle = !isResetEscape(token.raw);
|
|
305
|
+
}
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (visible + token.width > maxWidth) {
|
|
309
|
+
if (activeOsc8.length > 0)
|
|
310
|
+
result += OSC8_CLOSE;
|
|
311
|
+
if (hasStyle && !result.endsWith(RESET_SGR))
|
|
312
|
+
result += RESET_SGR;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
result += token.raw;
|
|
316
|
+
visible += token.width;
|
|
317
|
+
}
|
|
318
|
+
return activeOsc8.length > 0 || hasStyle
|
|
319
|
+
? finalizeTableWrappedLine(result, activeOsc8, hasStyle ? RESET_SGR : '')
|
|
320
|
+
: result;
|
|
321
|
+
}
|
|
322
|
+
function wrapCellToWidth(str, maxWidth) {
|
|
323
|
+
if (maxWidth <= 0)
|
|
324
|
+
return [''];
|
|
325
|
+
const tokens = tokenizeTableText(str);
|
|
326
|
+
if (tokens.length === 0)
|
|
327
|
+
return [''];
|
|
328
|
+
const lines = [];
|
|
329
|
+
let current = '';
|
|
330
|
+
let currentWidth = 0;
|
|
331
|
+
let activeStyle = '';
|
|
332
|
+
let activeOsc8 = '';
|
|
333
|
+
for (const token of tokens) {
|
|
334
|
+
if (token.kind === 'ansi') {
|
|
335
|
+
current += token.raw;
|
|
336
|
+
if (isOsc8Escape(token.raw)) {
|
|
337
|
+
activeOsc8 = isOsc8Close(token.raw) ? '' : token.raw;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
activeStyle = isResetEscape(token.raw) ? '' : activeStyle + token.raw;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (currentWidth + token.width > maxWidth && currentWidth > 0) {
|
|
344
|
+
lines.push(finalizeTableWrappedLine(current, activeOsc8, activeStyle));
|
|
345
|
+
current = activeTableAnsiPrefix(activeOsc8, activeStyle) + token.raw;
|
|
346
|
+
currentWidth = token.width;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
current += token.raw;
|
|
350
|
+
currentWidth += token.width;
|
|
351
|
+
}
|
|
352
|
+
if (current.length > 0) {
|
|
353
|
+
lines.push(finalizeTableWrappedLine(current, activeOsc8, activeStyle));
|
|
354
|
+
}
|
|
355
|
+
return lines.length > 0 ? lines : [''];
|
|
356
|
+
}
|
|
357
|
+
function buildFittedTable(options, ctx, tableData, variant, optionsOverride = {}) {
|
|
358
|
+
const columns = optionsOverride.columns ?? tableData.columns;
|
|
359
|
+
const rows = optionsOverride.rows ?? tableData.rows;
|
|
360
|
+
const layout = optionsOverride.layout ?? options.layout ?? 'auto';
|
|
361
|
+
const columnGap = sanitizeNonNegativeInt(options.columnGap, 2);
|
|
362
|
+
const overflow = resolveOverflowBehavior(options.overflow, ctx.resolveBCSS({ type: 'Table', id: options.id, classes: options.class?.split(' ') }));
|
|
363
|
+
const wrapMode = options.wrap ?? 'word';
|
|
364
|
+
const widths = fitColumnWidths(columns, rows, variant, layout, resolveTargetWidth(options, ctx, layout), columnGap);
|
|
365
|
+
const headerToken = options.headerToken ?? ctx.ui('tableHeader');
|
|
366
|
+
const styleHeaders = optionsOverride.styleHeaders ?? true;
|
|
367
|
+
const headerLines = columns.map((column, index) => {
|
|
368
|
+
const header = column.header ?? '';
|
|
369
|
+
const value = styleHeaders ? ctx.style.styled(headerToken, header) : header;
|
|
370
|
+
return formatCellLines(value, widths[index] ?? 0, overflow, wrapMode);
|
|
371
|
+
});
|
|
372
|
+
const headerHeight = headerLines.reduce((max, lines) => Math.max(max, lines.length), 1);
|
|
373
|
+
const fittedRows = rows.map((row) => {
|
|
374
|
+
const cells = widths.map((width, index) => {
|
|
375
|
+
return formatCellLines(row[index] ?? '', width, overflow, wrapMode);
|
|
376
|
+
});
|
|
377
|
+
const height = cells.reduce((max, lines) => Math.max(max, lines.length), 1);
|
|
378
|
+
return { cells, height };
|
|
379
|
+
});
|
|
380
|
+
return {
|
|
381
|
+
columns: columns.map((column, index) => ({
|
|
382
|
+
header: column.header ?? '',
|
|
383
|
+
width: widths[index] ?? 0,
|
|
384
|
+
align: column.align ?? 'left',
|
|
385
|
+
})),
|
|
386
|
+
widths,
|
|
387
|
+
headerLines,
|
|
388
|
+
headerHeight,
|
|
389
|
+
rows: fittedRows,
|
|
390
|
+
columnGap,
|
|
391
|
+
showHeader: tableData.showHeader,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function renderGridTable(model, options, ctx, variant, styled = true) {
|
|
395
|
+
const borderToken = options.borderToken ?? ctx.border('muted');
|
|
396
|
+
const bc = (s) => styled ? ctx.style.styled(borderToken, s) : s;
|
|
397
|
+
const chars = variant === 'box'
|
|
398
|
+
? {
|
|
399
|
+
h: '\u2500',
|
|
400
|
+
v: '\u2502',
|
|
401
|
+
topLeft: '\u250c',
|
|
402
|
+
topMid: '\u252c',
|
|
403
|
+
topRight: '\u2510',
|
|
404
|
+
midLeft: '\u251c',
|
|
405
|
+
midMid: '\u253c',
|
|
406
|
+
midRight: '\u2524',
|
|
407
|
+
bottomLeft: '\u2514',
|
|
408
|
+
bottomMid: '\u2534',
|
|
409
|
+
bottomRight: '\u2518',
|
|
410
|
+
}
|
|
411
|
+
: {
|
|
412
|
+
h: '-',
|
|
413
|
+
v: '|',
|
|
414
|
+
topLeft: '+',
|
|
415
|
+
topMid: '+',
|
|
416
|
+
topRight: '+',
|
|
417
|
+
midLeft: '+',
|
|
418
|
+
midMid: '+',
|
|
419
|
+
midRight: '+',
|
|
420
|
+
bottomLeft: '+',
|
|
421
|
+
bottomMid: '+',
|
|
422
|
+
bottomRight: '+',
|
|
423
|
+
};
|
|
424
|
+
const hLine = (left, mid, right) => {
|
|
425
|
+
const segments = model.widths.map(w => chars.h.repeat(w + 2));
|
|
426
|
+
return bc(left + segments.join(mid) + right);
|
|
427
|
+
};
|
|
428
|
+
const top = hLine(chars.topLeft, chars.topMid, chars.topRight);
|
|
429
|
+
const midSep = hLine(chars.midLeft, chars.midMid, chars.midRight);
|
|
430
|
+
const bottom = hLine(chars.bottomLeft, chars.bottomMid, chars.bottomRight);
|
|
431
|
+
const hdrBgFill = styled ? makeBgFill(options.headerBgToken, ctx) : undefined;
|
|
432
|
+
const headerRows = Array.from({ length: model.headerHeight }, (_row, rowIndex) => {
|
|
433
|
+
const headerCells = model.columns.map((column, i) => ' ' + alignCell(model.headerLines[i]?.[rowIndex] ?? '', column.width, column.align) + ' ');
|
|
434
|
+
const rawHeaderRow = bc(chars.v) + headerCells.join(bc(chars.v)) + bc(chars.v);
|
|
435
|
+
return hdrBgFill ? hdrBgFill(rawHeaderRow) : rawHeaderRow;
|
|
436
|
+
});
|
|
437
|
+
const dataRows = model.rows.flatMap((row) => {
|
|
438
|
+
return Array.from({ length: row.height }, (_line, lineIndex) => {
|
|
439
|
+
const cells = model.columns.map((column, i) => ' ' + alignCell(row.cells[i]?.[lineIndex] ?? '', column.width, column.align) + ' ');
|
|
440
|
+
return bc(chars.v) + cells.join(bc(chars.v)) + bc(chars.v);
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
return model.showHeader
|
|
444
|
+
? [top, ...headerRows, midSep, ...dataRows, bottom].join('\n')
|
|
445
|
+
: [top, ...dataRows, bottom].join('\n');
|
|
446
|
+
}
|
|
447
|
+
function renderBorderlessRow(model, cells, rowIndex) {
|
|
448
|
+
const gap = ' '.repeat(model.columnGap);
|
|
449
|
+
return model.columns
|
|
450
|
+
.map((column, index) => alignCell(cells[index]?.[rowIndex] ?? '', column.width, column.align))
|
|
451
|
+
.join(gap)
|
|
452
|
+
.trimEnd();
|
|
453
|
+
}
|
|
454
|
+
function renderRule(model, char, ctx, options) {
|
|
455
|
+
const borderToken = options.borderToken ?? ctx.border('muted');
|
|
456
|
+
const line = model.widths.map(width => char.repeat(width)).join(' '.repeat(model.columnGap)).trimEnd();
|
|
457
|
+
return ctx.style.styled(borderToken, line);
|
|
458
|
+
}
|
|
459
|
+
function renderRuledTable(model, options, ctx, includeRowRules) {
|
|
460
|
+
const lines = model.showHeader
|
|
461
|
+
? [
|
|
462
|
+
...Array.from({ length: model.headerHeight }, (_row, index) => {
|
|
463
|
+
return renderBorderlessRow(model, model.headerLines, index);
|
|
464
|
+
}),
|
|
465
|
+
renderRule(model, '\u2501', ctx, options),
|
|
466
|
+
]
|
|
467
|
+
: [];
|
|
468
|
+
for (let rowIndex = 0; rowIndex < model.rows.length; rowIndex++) {
|
|
469
|
+
const row = model.rows[rowIndex];
|
|
470
|
+
for (let lineIndex = 0; lineIndex < row.height; lineIndex++) {
|
|
471
|
+
lines.push(renderBorderlessRow(model, row.cells, lineIndex));
|
|
472
|
+
}
|
|
473
|
+
if (includeRowRules && rowIndex < model.rows.length - 1) {
|
|
474
|
+
lines.push(renderRule(model, '\u2500', ctx, options));
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return lines.join('\n');
|
|
478
|
+
}
|
|
479
|
+
function renderHeaderRuleTable(model) {
|
|
480
|
+
const lines = model.showHeader
|
|
481
|
+
? [
|
|
482
|
+
...Array.from({ length: model.headerHeight }, (_row, index) => {
|
|
483
|
+
return renderBorderlessRow(model, model.headerLines, index);
|
|
484
|
+
}),
|
|
485
|
+
model.widths.map(width => '-'.repeat(width)).join(' '.repeat(model.columnGap)).trimEnd(),
|
|
486
|
+
]
|
|
487
|
+
: [];
|
|
488
|
+
for (const row of model.rows) {
|
|
489
|
+
for (let lineIndex = 0; lineIndex < row.height; lineIndex++) {
|
|
490
|
+
lines.push(renderBorderlessRow(model, row.cells, lineIndex));
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return lines.join('\n');
|
|
494
|
+
}
|
|
495
|
+
function renderPlainTable(model) {
|
|
496
|
+
const lines = model.showHeader
|
|
497
|
+
? Array.from({ length: model.headerHeight }, (_row, index) => {
|
|
498
|
+
return renderBorderlessRow(model, model.headerLines, index);
|
|
499
|
+
})
|
|
500
|
+
: [];
|
|
501
|
+
for (const row of model.rows) {
|
|
502
|
+
for (let lineIndex = 0; lineIndex < row.height; lineIndex++) {
|
|
503
|
+
lines.push(renderBorderlessRow(model, row.cells, lineIndex));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return lines.join('\n');
|
|
507
|
+
}
|
|
508
|
+
function markdownSeparator(width, align) {
|
|
509
|
+
const segmentWidth = Math.max(3, width + 2);
|
|
510
|
+
if (align === 'right')
|
|
511
|
+
return '-'.repeat(segmentWidth - 1) + ':';
|
|
512
|
+
if (align === 'center')
|
|
513
|
+
return ':' + '-'.repeat(segmentWidth - 2) + ':';
|
|
514
|
+
return '-'.repeat(segmentWidth);
|
|
515
|
+
}
|
|
516
|
+
function renderMarkdownTable(model) {
|
|
517
|
+
const renderWidths = model.columns.map(column => Math.max(1, column.width));
|
|
518
|
+
const rowLine = (cells, lineIndex) => {
|
|
519
|
+
return '|' + model.columns.map((column, index) => {
|
|
520
|
+
const value = cells[index]?.[lineIndex] ?? '';
|
|
521
|
+
return ' ' + alignCell(value, renderWidths[index], column.align) + ' ';
|
|
522
|
+
}).join('|') + '|';
|
|
523
|
+
};
|
|
524
|
+
const headerRows = Array.from({ length: model.headerHeight }, (_row, index) => {
|
|
525
|
+
return rowLine(model.headerLines, index);
|
|
526
|
+
});
|
|
527
|
+
const separator = '|' + model.columns.map((column, index) => {
|
|
528
|
+
return markdownSeparator(renderWidths[index], column.align);
|
|
529
|
+
}).join('|') + '|';
|
|
530
|
+
const rows = model.rows.flatMap((row) => {
|
|
531
|
+
return Array.from({ length: row.height }, (_line, index) => rowLine(row.cells, index));
|
|
532
|
+
});
|
|
533
|
+
return model.showHeader ? [...headerRows, separator, ...rows].join('\n') : rows.join('\n');
|
|
534
|
+
}
|
|
535
|
+
function renderExpandedTable(tableData, options, ctx) {
|
|
536
|
+
const borderToken = options.borderToken ?? ctx.border('muted');
|
|
537
|
+
const lines = [];
|
|
538
|
+
const columnLabel = (index) => {
|
|
539
|
+
return tableData.showHeader ? tableData.columns[index]?.header ?? '' : `Column ${index + 1}`;
|
|
540
|
+
};
|
|
541
|
+
const preferredLabelWidth = tableData.columns.reduce((max, _column, index) => {
|
|
542
|
+
return Math.max(max, visibleLength(columnLabel(index)));
|
|
543
|
+
}, 0);
|
|
544
|
+
const layout = options.layout ?? 'auto';
|
|
545
|
+
const targetWidth = resolveTargetWidth(options, ctx, layout);
|
|
546
|
+
const ruleWidth = targetWidth ?? 40;
|
|
547
|
+
const separator = targetWidth === undefined || targetWidth >= 3
|
|
548
|
+
? ' | '
|
|
549
|
+
: ' '.repeat(Math.max(0, targetWidth - 1));
|
|
550
|
+
const availableContentWidth = targetWidth === undefined
|
|
551
|
+
? undefined
|
|
552
|
+
: Math.max(0, targetWidth - separator.length);
|
|
553
|
+
const labelWidth = targetWidth === undefined
|
|
554
|
+
? preferredLabelWidth
|
|
555
|
+
: Math.min(preferredLabelWidth, Math.floor((availableContentWidth ?? 0) / 2));
|
|
556
|
+
const valueWidth = targetWidth === undefined
|
|
557
|
+
? undefined
|
|
558
|
+
: Math.max(0, targetWidth - labelWidth - separator.length);
|
|
559
|
+
const overflow = resolveOverflowBehavior(options.overflow, ctx.resolveBCSS({ type: 'Table', id: options.id, classes: options.class?.split(' ') }));
|
|
560
|
+
const wrapMode = options.wrap ?? 'word';
|
|
561
|
+
for (let rowIndex = 0; rowIndex < tableData.rows.length; rowIndex++) {
|
|
562
|
+
const title = `-[ RECORD ${rowIndex + 1} ]`;
|
|
563
|
+
const clippedTitle = targetWidth === undefined ? title : clipCellToWidth(title, ruleWidth);
|
|
564
|
+
lines.push(ctx.style.styled(borderToken, clippedTitle + '-'.repeat(Math.max(0, ruleWidth - visibleLength(clippedTitle)))));
|
|
565
|
+
const row = tableData.rows[rowIndex];
|
|
566
|
+
for (let columnIndex = 0; columnIndex < tableData.columns.length; columnIndex++) {
|
|
567
|
+
const rawLabel = columnLabel(columnIndex);
|
|
568
|
+
const label = padRight(targetWidth === undefined ? rawLabel : clipCellToWidth(rawLabel, labelWidth), labelWidth);
|
|
569
|
+
const rawValue = row[columnIndex] ?? '';
|
|
570
|
+
const valueLines = valueWidth === undefined
|
|
571
|
+
? rawValue.split('\n')
|
|
572
|
+
: formatCellLines(rawValue, valueWidth, overflow, wrapMode);
|
|
573
|
+
for (let lineIndex = 0; lineIndex < valueLines.length; lineIndex++) {
|
|
574
|
+
const lineLabel = lineIndex === 0 ? label : ' '.repeat(labelWidth);
|
|
575
|
+
lines.push(`${lineLabel}${separator}${valueLines[lineIndex] ?? ''}`.trimEnd());
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return lines.join('\n');
|
|
580
|
+
}
|
|
581
|
+
function markdownEscapeCell(value) {
|
|
582
|
+
return stripAnsi(String(value ?? ''))
|
|
583
|
+
.replace(/\\/g, '\\\\')
|
|
584
|
+
.replace(/\|/g, '\\|')
|
|
585
|
+
.replace(/\r\n?/g, '\n')
|
|
586
|
+
.replace(/\n/g, '<br>');
|
|
587
|
+
}
|
|
588
|
+
function markdownTableData(tableData) {
|
|
589
|
+
return {
|
|
590
|
+
columns: tableData.columns.map(column => ({
|
|
591
|
+
...column,
|
|
592
|
+
header: markdownEscapeCell(column.header ?? ''),
|
|
593
|
+
})),
|
|
594
|
+
rows: tableData.rows.map(row => row.map(cell => markdownEscapeCell(cell))),
|
|
595
|
+
showHeader: tableData.showHeader,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function renderVisualTable(options, ctx, tableData, variant) {
|
|
599
|
+
if (variant === 'markdown') {
|
|
600
|
+
const markdownData = markdownTableData(tableData);
|
|
601
|
+
const markdownModel = buildFittedTable(options, ctx, markdownData, 'markdown', {
|
|
602
|
+
styleHeaders: false,
|
|
603
|
+
});
|
|
604
|
+
return renderMarkdownTable(markdownModel);
|
|
605
|
+
}
|
|
606
|
+
if (variant === 'expanded') {
|
|
607
|
+
return renderExpandedTable(tableData, options, ctx);
|
|
608
|
+
}
|
|
609
|
+
const model = buildFittedTable(options, ctx, tableData, variant);
|
|
610
|
+
switch (variant) {
|
|
611
|
+
case 'ascii-grid':
|
|
612
|
+
return renderGridTable(model, options, ctx, 'ascii-grid');
|
|
613
|
+
case 'ruled':
|
|
614
|
+
return renderRuledTable(model, options, ctx, true);
|
|
615
|
+
case 'header-rule':
|
|
616
|
+
return renderHeaderRuleTable(model);
|
|
617
|
+
case 'plain':
|
|
618
|
+
return renderPlainTable(model);
|
|
619
|
+
case 'definition':
|
|
620
|
+
return renderRuledTable(model, options, ctx, true);
|
|
621
|
+
case 'box':
|
|
622
|
+
default:
|
|
623
|
+
return renderGridTable(model, options, ctx, 'box');
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function escapeTsvCell(value) {
|
|
627
|
+
return String(value ?? '')
|
|
628
|
+
.replace(/\\/g, '\\\\')
|
|
629
|
+
.replace(/\t/g, '\\t')
|
|
630
|
+
.replace(/\r/g, '\\r')
|
|
631
|
+
.replace(/\n/g, '\\n');
|
|
632
|
+
}
|
|
633
|
+
function escapeCsvCell(value) {
|
|
634
|
+
const text = String(value ?? '');
|
|
635
|
+
if (!/[",\r\n]/.test(text))
|
|
636
|
+
return text;
|
|
637
|
+
return `"${text.replace(/"/g, '""')}"`;
|
|
638
|
+
}
|
|
639
|
+
function renderSeparatedPipe(tableData, separator, escapeCell) {
|
|
640
|
+
const headerLine = tableData.columns.map(column => escapeCell(column.header ?? '')).join(separator);
|
|
641
|
+
const dataLines = tableData.rows.map(row => row.map(escapeCell).join(separator));
|
|
642
|
+
if (!tableData.showHeader)
|
|
643
|
+
return dataLines.join('\n');
|
|
644
|
+
return [headerLine, ...dataLines].join('\n');
|
|
645
|
+
}
|
|
646
|
+
function renderPipeTable(options, ctx, tableData) {
|
|
647
|
+
const format = options.pipeFormat ?? 'tsv';
|
|
648
|
+
if (format === 'csv')
|
|
649
|
+
return renderSeparatedPipe(tableData, ',', escapeCsvCell);
|
|
650
|
+
if (format === 'markdown') {
|
|
651
|
+
const markdownData = markdownTableData(tableData);
|
|
652
|
+
const markdownModel = buildFittedTable(options, ctx, markdownData, 'markdown', {
|
|
653
|
+
layout: options.layout ?? (options.width !== undefined || options.maxWidth !== undefined ? 'auto' : 'intrinsic'),
|
|
654
|
+
styleHeaders: false,
|
|
655
|
+
});
|
|
656
|
+
return renderMarkdownTable(markdownModel);
|
|
657
|
+
}
|
|
658
|
+
if (format === 'ascii-grid') {
|
|
659
|
+
const model = buildFittedTable(options, ctx, tableData, 'ascii-grid', {
|
|
660
|
+
layout: options.layout ?? (options.width !== undefined || options.maxWidth !== undefined ? 'auto' : 'intrinsic'),
|
|
661
|
+
styleHeaders: false,
|
|
662
|
+
});
|
|
663
|
+
return renderGridTable(model, options, ctx, 'ascii-grid', false);
|
|
664
|
+
}
|
|
665
|
+
return renderSeparatedPipe(tableData, '\t', escapeTsvCell);
|
|
666
|
+
}
|
|
667
|
+
export function table(optionsOrColumns, rowData, context) {
|
|
668
|
+
let options;
|
|
669
|
+
if (isTableOptions(optionsOrColumns)) {
|
|
670
|
+
options = optionsOrColumns;
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
options = { columns: [...optionsOrColumns], rows: rowData ?? [], ctx: context };
|
|
674
|
+
}
|
|
56
675
|
const ctx = resolveCtx(options.ctx);
|
|
57
|
-
const
|
|
58
|
-
const rows = (options.rows ?? []).map(row => (row ?? []).map(cell => cell ?? ''));
|
|
676
|
+
const tableData = normalizeTable(options);
|
|
59
677
|
return renderByMode(ctx.mode, {
|
|
60
|
-
pipe: () =>
|
|
61
|
-
const headerLine = columns.map((c) => c.header ?? '').join('\t');
|
|
62
|
-
const dataLines = rows.map((row) => row.join('\t'));
|
|
63
|
-
return [headerLine, ...dataLines].join('\n');
|
|
64
|
-
},
|
|
678
|
+
pipe: () => renderPipeTable(options, ctx, tableData),
|
|
65
679
|
accessible: () => {
|
|
66
680
|
const lines = [];
|
|
67
|
-
for (let i = 0; i < rows.length; i++) {
|
|
68
|
-
const row = rows[i];
|
|
69
|
-
const pairs = columns.map((col, j) =>
|
|
681
|
+
for (let i = 0; i < tableData.rows.length; i++) {
|
|
682
|
+
const row = tableData.rows[i];
|
|
683
|
+
const pairs = tableData.columns.map((col, j) => {
|
|
684
|
+
const label = tableData.showHeader ? col.header ?? '' : `Column ${j + 1}`;
|
|
685
|
+
return `${label}=${row[j] ?? ''}`;
|
|
686
|
+
});
|
|
70
687
|
lines.push(`Row ${i + 1}: ${pairs.join(', ')}`);
|
|
71
688
|
}
|
|
72
689
|
return lines.join('\n');
|
|
73
690
|
},
|
|
74
|
-
interactive: () =>
|
|
75
|
-
const headerToken = options.headerToken ?? ctx.ui('tableHeader');
|
|
76
|
-
const borderToken = options.borderToken ?? ctx.border('muted');
|
|
77
|
-
const overflow = resolveOverflowBehavior(options.overflow, ctx.resolveBCSS({ type: 'Table', id: options.id, classes: options.class?.split(' ') }));
|
|
78
|
-
const bc = (s) => ctx.style.styled(borderToken, s);
|
|
79
|
-
const colWidths = columns.map((col, i) => {
|
|
80
|
-
const normalizedWidth = normalizeColumnWidth(col.width);
|
|
81
|
-
if (normalizedWidth !== undefined)
|
|
82
|
-
return normalizedWidth;
|
|
83
|
-
let max = visibleLength(col.header ?? '');
|
|
84
|
-
for (const row of rows) {
|
|
85
|
-
const cell = row[i] ?? '';
|
|
86
|
-
max = Math.max(max, visibleLength(cell));
|
|
87
|
-
}
|
|
88
|
-
return max;
|
|
89
|
-
});
|
|
90
|
-
const h = '\u2500';
|
|
91
|
-
const v = '\u2502';
|
|
92
|
-
const hLine = (left, mid, right) => {
|
|
93
|
-
const segments = colWidths.map((w) => h.repeat(w + 2));
|
|
94
|
-
return bc(left + segments.join(mid) + right);
|
|
95
|
-
};
|
|
96
|
-
const top = hLine('\u250c', '\u252c', '\u2510');
|
|
97
|
-
const midSep = hLine('\u251c', '\u253c', '\u2524');
|
|
98
|
-
const bottom = hLine('\u2514', '\u2534', '\u2518');
|
|
99
|
-
const hdrBgFill = makeBgFill(options.headerBgToken, ctx);
|
|
100
|
-
const headerLinesByColumn = columns.map((col, i) => formatCellLines(ctx.style.styled(headerToken, col.header ?? ''), colWidths[i], overflow, col.width !== undefined));
|
|
101
|
-
const headerHeight = headerLinesByColumn.reduce((max, lines) => Math.max(max, lines.length), 1);
|
|
102
|
-
const headerRows = Array.from({ length: headerHeight }, (_row, rowIndex) => {
|
|
103
|
-
const headerCells = columns.map((_col, i) => ' ' + padRight(headerLinesByColumn[i][rowIndex] ?? '', colWidths[i]) + ' ');
|
|
104
|
-
const rawHeaderRow = bc(v) + headerCells.join(bc(v)) + bc(v);
|
|
105
|
-
return hdrBgFill ? hdrBgFill(rawHeaderRow) : rawHeaderRow;
|
|
106
|
-
});
|
|
107
|
-
const dataRows = rows.flatMap((row) => {
|
|
108
|
-
const cellLines = colWidths.map((w, i) => formatCellLines(row[i] ?? '', w, overflow, columns[i]?.width !== undefined));
|
|
109
|
-
const rowHeight = cellLines.reduce((max, lines) => Math.max(max, lines.length), 1);
|
|
110
|
-
return Array.from({ length: rowHeight }, (_line, lineIndex) => {
|
|
111
|
-
const cells = colWidths.map((w, i) => ' ' + padRight(cellLines[i][lineIndex] ?? '', w) + ' ');
|
|
112
|
-
return bc(v) + cells.join(bc(v)) + bc(v);
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
const lines = [top, ...headerRows, midSep, ...dataRows, bottom];
|
|
116
|
-
return lines.join('\n');
|
|
117
|
-
},
|
|
691
|
+
interactive: () => renderVisualTable(options, ctx, tableData, options.variant ?? 'box'),
|
|
118
692
|
}, options);
|
|
119
693
|
}
|
|
120
694
|
//# sourceMappingURL=table.js.map
|