Skip to content

Commit

Permalink
feat: preprocess and postprocess (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber committed Jan 4, 2022
1 parent 21b8681 commit 05dfbcf
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 3 deletions.
30 changes: 30 additions & 0 deletions README.md
Expand Up @@ -155,6 +155,26 @@ terminalColumns(
)
```

### Preprocess / Postprocess
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.

In this example, the first column spans the entire screen and is transformed to be uppercase on screens smaller than 80 columns.

```ts
terminalColumns(
tableData,
breakpoints({
// Small screens
'< 80': [
{
width: '100%',
preprocess: text => text.toUpperCase()
},
'100%'
]
})
)
```

### Responsive table with custom function
You can make the table responsive by passing in a function that computes the column width allocation based on the detected viewport width.
Expand Down Expand Up @@ -314,6 +334,16 @@ Default: `'left'`
Whether to align the text to the left or right.
##### preprocess
Type: `(cellValue: string) => string`
Function to preprocess the cell value before it is wrapped to the column width.
##### postprocess
Type: `(line: string, lineNumber: number) => string`
Function to postprocess the individual lines of a cell after it has been wrapped to the column width.
### breakpoints(breakpointsMap)
A function to declaratively define breakpoints. Returns a function pass into terminal-columns.
Expand Down
17 changes: 15 additions & 2 deletions src/types.ts
Expand Up @@ -4,16 +4,29 @@ export type ColumnWidth = number | 'content-width' | 'auto' | string;

type Alignment = 'left' | 'right';

export type ColumnMeta<Width = ColumnWidth> ={
export type ColumnMeta<Width = ColumnWidth> = {
width?: Width;
align?: Alignment;
paddingRight?: number;
paddingLeft?: number;
paddingTop?: number;
paddingBottom?: number;
preprocess?: (cellValue: string) => string;
postprocess?: (line: string, lineNumber: number) => string;
};

export type InternalColumnMeta<Width = ColumnWidth> = Required<ColumnMeta<Width>> & {
export type InternalColumnMeta<Width = ColumnWidth> = {
// Options
width: Width;
align: Alignment;
paddingRight: number;
paddingLeft: number;
paddingTop: number;
paddingBottom: number;
preprocess?: ((cellValue: string) => string);
postprocess?: ((line: string, lineNumber: number) => string);

// Internal meta data
autoOverflow?: number;
contentWidth: number;
paddingLeftString: string;
Expand Down
14 changes: 13 additions & 1 deletion src/utils/render-row.ts
Expand Up @@ -21,13 +21,24 @@ export function renderRow(
let cellText = rowData[columnIndex] ?? '';
columnIndex += 1;

if (column.preprocess) {
cellText = column.preprocess(cellText);
}

if (getLongestLineWidth(cellText) > column.width) {
cellText = wrapAnsi(cellText, column.width, {
hard: true,
});
}

const lines = cellText.split('\n');
let lines = cellText.split('\n');

if (column.postprocess) {
const { postprocess } = column;
lines = lines.map(
(line, lineNumber) => postprocess.call(column, line, lineNumber),
);
}

if (column.paddingTop) {
lines.unshift(...emptyLines(column.paddingTop));
Expand All @@ -52,6 +63,7 @@ export function renderRow(
const rowLine = subRowWithData
.map((column) => {
const cellLine = column.lines[i] ?? '';

const lineFiller = ' '.repeat(column.width - stringWidth(cellLine));
let text = column.paddingLeftString;

Expand Down
31 changes: 31 additions & 0 deletions tests/__snapshots__/terminal-columns.spec.ts.snap
Expand Up @@ -359,6 +359,37 @@ exports[`percent widths 100% 100% with padding 1`] = `
"
`;

exports[`process postprocess 1`] = `
"LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT, SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE
et dolore magna aliqua.
DICTUMST QUISQUE SAGITTIS PURUS SIT AMET VOLUTPAT CONSEQUAT MAURIS NUNC.
nunc sed augue lacus viverra vitae congue eu consequat ac.
SIT AMET PORTTITOR EGET DOLOR MORBI NON ARCU. "
`;

exports[`process postprocess ignores vertical padding 1`] = `
" Lorem ipsum dolor sit amet, consectetur adipiscing
postprocessed elit, sed do eiusmod tempor incididunt ut labore
postprocessed et dolore magna aliqua.
postprocessed Dictumst quisque sagittis purus sit amet volutpat
postprocessed consequat mauris nunc.
postprocessed Nunc sed augue lacus viverra vitae congue eu
postprocessed consequat ac.
postprocessed Sit amet porttitor eget dolor morbi non arcu.
postprocessed
"
`;

exports[`process preprocess 1`] = `
"LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT, SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE
ET DOLORE MAGNA ALIQUA.
DICTUMST QUISQUE SAGITTIS PURUS SIT AMET VOLUTPAT CONSEQUAT MAURIS NUNC.
NUNC SED AUGUE LACUS VIVERRA VITAE CONGUE EU CONSEQUAT AC.
SIT AMET PORTTITOR EGET DOLOR MORBI NON ARCU. "
`;

exports[`static widths fixed width 1`] = `
"Lorem Lorem ipsum dolor
ipsum sit amet,
Expand Down
61 changes: 61 additions & 0 deletions tests/terminal-columns.spec.ts
Expand Up @@ -158,6 +158,67 @@ describe('align', () => {
});
});

describe('process', () => {
test('preprocess', () => {
const table = terminalColumns(
[
[
loremIpsumNewLines,
],
],
[
{
preprocess: text => text.toUpperCase(),
},
],
);

expect(table).toMatchSnapshot();
});

test('postprocess', () => {
const table = terminalColumns(
[
[
loremIpsumNewLines,
],
],
[
{
postprocess: (line, i) => {
if (i % 2 === 0) {
return line.toUpperCase();
}
return line.toLowerCase();
},
},
],
);

expect(table).toMatchSnapshot();
});

test('postprocess ignores vertical padding', () => {
const table = terminalColumns(
[
[
loremIpsumNewLines,
loremIpsumNewLines,
],
],
[
{
postprocess: () => 'postprocessed',
paddingTop: 1,
paddingBottom: 3,
},
],
);

expect(table).toMatchSnapshot();
});
});

describe('static widths', () => {
test('fixed width', () => {
const table = terminalColumns(
Expand Down

0 comments on commit 05dfbcf

Please sign in to comment.