Skip to content

Commit 5c4f841

Browse files
committed
Merge branch 'develop' of github.com:privatenumber/terminal-columns
2 parents ad9b032 + 05dfbcf commit 5c4f841

File tree

5 files changed

+177
-3
lines changed

5 files changed

+177
-3
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,26 @@ terminalColumns(
155155
)
156156
```
157157

158+
### Preprocess / Postprocess
159+
Preprocessing and postprocessing can be used to modify the table data before it is rendered. It's primarily designed for formatting purposes and can be useful to style text in a declarative manner.
160+
161+
In this example, the first column spans the entire screen and is transformed to be uppercase on screens smaller than 80 columns.
162+
163+
```ts
164+
terminalColumns(
165+
tableData,
166+
breakpoints({
167+
// Small screens
168+
'< 80': [
169+
{
170+
width: '100%',
171+
preprocess: text => text.toUpperCase()
172+
},
173+
'100%'
174+
]
175+
})
176+
)
177+
```
158178

159179
### Responsive table with custom function
160180
You can make the table responsive by passing in a function that computes the column width allocation based on the detected viewport width.
@@ -314,6 +334,16 @@ Default: `'left'`
314334
315335
Whether to align the text to the left or right.
316336
337+
##### preprocess
338+
Type: `(cellValue: string) => string`
339+
340+
Function to preprocess the cell value before it is wrapped to the column width.
341+
342+
##### postprocess
343+
Type: `(line: string, lineNumber: number) => string`
344+
345+
Function to postprocess the individual lines of a cell after it has been wrapped to the column width.
346+
317347
### breakpoints(breakpointsMap)
318348
319349
A function to declaratively define breakpoints. Returns a function pass into terminal-columns.

src/types.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,29 @@ export type ColumnWidth = number | 'content-width' | 'auto' | string;
44

55
type Alignment = 'left' | 'right';
66

7-
export type ColumnMeta<Width = ColumnWidth> ={
7+
export type ColumnMeta<Width = ColumnWidth> = {
88
width?: Width;
99
align?: Alignment;
1010
paddingRight?: number;
1111
paddingLeft?: number;
1212
paddingTop?: number;
1313
paddingBottom?: number;
14+
preprocess?: (cellValue: string) => string;
15+
postprocess?: (line: string, lineNumber: number) => string;
1416
};
1517

16-
export type InternalColumnMeta<Width = ColumnWidth> = Required<ColumnMeta<Width>> & {
18+
export type InternalColumnMeta<Width = ColumnWidth> = {
19+
// Options
20+
width: Width;
21+
align: Alignment;
22+
paddingRight: number;
23+
paddingLeft: number;
24+
paddingTop: number;
25+
paddingBottom: number;
26+
preprocess?: ((cellValue: string) => string);
27+
postprocess?: ((line: string, lineNumber: number) => string);
28+
29+
// Internal meta data
1730
autoOverflow?: number;
1831
contentWidth: number;
1932
paddingLeftString: string;

src/utils/render-row.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,24 @@ export function renderRow(
2121
let cellText = rowData[columnIndex] ?? '';
2222
columnIndex += 1;
2323

24+
if (column.preprocess) {
25+
cellText = column.preprocess(cellText);
26+
}
27+
2428
if (getLongestLineWidth(cellText) > column.width) {
2529
cellText = wrapAnsi(cellText, column.width, {
2630
hard: true,
2731
});
2832
}
2933

30-
const lines = cellText.split('\n');
34+
let lines = cellText.split('\n');
35+
36+
if (column.postprocess) {
37+
const { postprocess } = column;
38+
lines = lines.map(
39+
(line, lineNumber) => postprocess.call(column, line, lineNumber),
40+
);
41+
}
3142

3243
if (column.paddingTop) {
3344
lines.unshift(...emptyLines(column.paddingTop));
@@ -52,6 +63,7 @@ export function renderRow(
5263
const rowLine = subRowWithData
5364
.map((column) => {
5465
const cellLine = column.lines[i] ?? '';
66+
5567
const lineFiller = ' '.repeat(column.width - stringWidth(cellLine));
5668
let text = column.paddingLeftString;
5769

tests/__snapshots__/terminal-columns.spec.ts.snap

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`align align right 1`] = `
4+
" Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
5+
et dolore magna aliqua.
6+
Dictumst quisque sagittis purus sit amet volutpat consequat mauris nunc.
7+
Nunc sed augue lacus viverra vitae congue eu consequat ac.
8+
Sit amet porttitor eget dolor morbi non arcu."
9+
`;
10+
311
exports[`auto event split - many 1`] = `
412
"Lorem ipsum dolor Lorem ipsum dolor Lorem ipsum dolor Lorem ipsum dolor Lorem ipsum dolor
513
sit amet. sit amet. sit amet. sit amet. sit amet.
@@ -351,6 +359,37 @@ exports[`percent widths 100% 100% with padding 1`] = `
351359
"
352360
`;
353361

362+
exports[`process postprocess 1`] = `
363+
"LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT, SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE
364+
et dolore magna aliqua.
365+
DICTUMST QUISQUE SAGITTIS PURUS SIT AMET VOLUTPAT CONSEQUAT MAURIS NUNC.
366+
nunc sed augue lacus viverra vitae congue eu consequat ac.
367+
SIT AMET PORTTITOR EGET DOLOR MORBI NON ARCU. "
368+
`;
369+
370+
exports[`process postprocess ignores vertical padding 1`] = `
371+
" Lorem ipsum dolor sit amet, consectetur adipiscing
372+
postprocessed elit, sed do eiusmod tempor incididunt ut labore
373+
postprocessed et dolore magna aliqua.
374+
postprocessed Dictumst quisque sagittis purus sit amet volutpat
375+
postprocessed consequat mauris nunc.
376+
postprocessed Nunc sed augue lacus viverra vitae congue eu
377+
postprocessed consequat ac.
378+
postprocessed Sit amet porttitor eget dolor morbi non arcu.
379+
postprocessed
380+
381+
382+
"
383+
`;
384+
385+
exports[`process preprocess 1`] = `
386+
"LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT, SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE
387+
ET DOLORE MAGNA ALIQUA.
388+
DICTUMST QUISQUE SAGITTIS PURUS SIT AMET VOLUTPAT CONSEQUAT MAURIS NUNC.
389+
NUNC SED AUGUE LACUS VIVERRA VITAE CONGUE EU CONSEQUAT AC.
390+
SIT AMET PORTTITOR EGET DOLOR MORBI NON ARCU. "
391+
`;
392+
354393
exports[`static widths fixed width 1`] = `
355394
"Lorem Lorem ipsum dolor
356395
ipsum sit amet,

tests/terminal-columns.spec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,86 @@ describe('padding', () => {
139139
});
140140
});
141141

142+
describe('align', () => {
143+
test('align right', () => {
144+
const table = terminalColumns(
145+
[
146+
[
147+
loremIpsumNewLines,
148+
],
149+
],
150+
[
151+
{
152+
align: 'right',
153+
},
154+
],
155+
);
156+
157+
expect(table).toMatchSnapshot();
158+
});
159+
});
160+
161+
describe('process', () => {
162+
test('preprocess', () => {
163+
const table = terminalColumns(
164+
[
165+
[
166+
loremIpsumNewLines,
167+
],
168+
],
169+
[
170+
{
171+
preprocess: text => text.toUpperCase(),
172+
},
173+
],
174+
);
175+
176+
expect(table).toMatchSnapshot();
177+
});
178+
179+
test('postprocess', () => {
180+
const table = terminalColumns(
181+
[
182+
[
183+
loremIpsumNewLines,
184+
],
185+
],
186+
[
187+
{
188+
postprocess: (line, i) => {
189+
if (i % 2 === 0) {
190+
return line.toUpperCase();
191+
}
192+
return line.toLowerCase();
193+
},
194+
},
195+
],
196+
);
197+
198+
expect(table).toMatchSnapshot();
199+
});
200+
201+
test('postprocess ignores vertical padding', () => {
202+
const table = terminalColumns(
203+
[
204+
[
205+
loremIpsumNewLines,
206+
loremIpsumNewLines,
207+
],
208+
],
209+
[
210+
{
211+
postprocess: () => 'postprocessed',
212+
paddingTop: 1,
213+
paddingBottom: 3,
214+
},
215+
],
216+
);
217+
218+
expect(table).toMatchSnapshot();
219+
});
220+
});
221+
142222
describe('static widths', () => {
143223
test('fixed width', () => {
144224
const table = terminalColumns(

0 commit comments

Comments
 (0)