Skip to content

Commit

Permalink
feat(table): parse table string
Browse files Browse the repository at this point in the history
  • Loading branch information
surunzi committed Nov 18, 2024
1 parent 303f82f commit 398bbc6
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 8 deletions.
10 changes: 10 additions & 0 deletions DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -13210,6 +13210,16 @@ function table(
|options|Table options|
|return |Table string |

### parse

Parse table string back to object.

|Name |Type |
|-------|-------------|
|table |Table string |
|options|Table options|
|return |Table data |

```javascript
table([
['', 'firstName', 'lastName'],
Expand Down
10 changes: 9 additions & 1 deletion DOC_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13198,9 +13198,17 @@ function table(
|参数名|说明|
|-----|---|
|rows|表格数据|
|options|选项|
|options|表格选项|
|返回值|表格字符串|

### parse

|参数名|说明|
|-----|---|
|table|表格字符串|
|options|表格选项|
|返回值|表格数据|

```javascript
table([
['', 'firstName', 'lastName'],
Expand Down
10 changes: 9 additions & 1 deletion i18n/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,13 @@
|参数名|说明|
|-----|---|
|rows|表格数据|
|options|选项|
|options|表格选项|
|返回值|表格字符串|

### parse

|参数名|说明|
|-----|---|
|table|表格字符串|
|options|表格选项|
|返回值|表格数据|
6 changes: 5 additions & 1 deletion index.json
Original file line number Diff line number Diff line change
Expand Up @@ -6413,7 +6413,11 @@
"map",
"repeat",
"cloneDeep",
"defaults"
"defaults",
"trim",
"rtrim",
"filter",
"last"
],
"description": "Output table string.",
"env": [
Expand Down
120 changes: 119 additions & 1 deletion src/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
* |rows |Table data |
* |options|Table options|
* |return |Table string |
*
* ### parse
*
* Parse table string back to object.
*
* |Name |Type |
* |-------|-------------|
* |table |Table string |
* |options|Table options|
* |return |Table data |
*/

/* example
Expand Down Expand Up @@ -50,7 +60,7 @@
* ): string;
*/

_('each strWidth map repeat cloneDeep defaults');
_('each strWidth map repeat cloneDeep defaults trim rtrim filter last');

exports = function(rows, options = {}) {
rows = cloneDeep(rows);
Expand Down Expand Up @@ -158,6 +168,114 @@ function renderBorder(type, options) {
return ret;
}

exports.parse = function(table, options = {}) {
options.border = options.border || {};
defaults(options.border, defBorder);
const lines = splitLines(table, options.border);

return parseLines(lines, options);
};

function splitLines(table, border) {
const lines = table.split(/\n/);
const trimLines = [];
let chars = ' ';
each(border, val => (chars += val));
each(lines, (line, idx) => {
line = trim(line);
line = trim(line, chars);
trimLines[idx] = line;
});

return filter(lines, (line, idx) => trimLines[idx] !== '');
}

function parseLines(lines, options) {
const { border } = options;

let maxLen = 0;
each(lines, line => {
const len = strWidth(line);
if (len > maxLen) {
maxLen = len;
}
});
lines = map(lines, line => line + repeat(' ', maxLen - strWidth(line)));

let start = -1;
let end = -1;
const firstLine = lines[0];
if (border.bodyLeft) {
start = firstLine.indexOf(border.bodyLeft);
}
if (border.bodyRight) {
end = firstLine.lastIndexOf(border.bodyRight);
}
lines = map(lines, line => {
if (start > -1) {
if (end > -1) {
line = line.slice(start + 1, end);
} else {
line = line.slice(start + 1);
}
}
return line;
});
maxLen = lines[0].length;

const rows = [];
const rowCount = lines.length;
let column = [];
for (let i = 0; i < maxLen; i++) {
let isSeparator = true;
let isFakeColumn = false;

for (let r = 0; r < rowCount; r++) {
column[r] = column[r] || '';
const c = lines[r][i] || '';
if (c !== border.bodyJoin) {
isSeparator = false;
}
column[r] += lines[r][i];
}

if (isSeparator || i === maxLen - 1) {
let emptyLineCount = 0;
each(column, data => {
data = rtrim(data, ' ' + border.bodyJoin);
if (data === '') {
emptyLineCount++;
}
});
if (emptyLineCount >= rowCount - 1) {
isFakeColumn = true;
}
if (isSeparator) {
column = map(column, data => data.slice(0, data.length - 1));
}

column = map(column, data => trim(data));
for (let r = 0; r < rowCount; r++) {
const row = rows[r] || [];
const data = column[r];

if (isFakeColumn) {
if (row.length !== 0 && data) {
row[row.length - 1] += border.bodyJoin + data;
}
} else {
row.push(data);
}

rows[r] = row;
}
column = [];
}
}

return rows;
}

const defBorder = {
topBody: '─',
topJoin: '┬',
Expand Down
123 changes: 119 additions & 4 deletions test/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ it('stringify', () => {
│ father │ John │ Smith │
├──────────┼───────────┼──────────┤
│ mother │ Jane │ Smith │
└──────────┴───────────┴──────────┘
`
└──────────┴───────────┴──────────┘`
]);
});

Expand All @@ -44,7 +43,123 @@ it('custom table borders', () => {
│ father John Smith │
├─────────────────────────────────┤
│ mother Jane Smith │
└─────────────────────────────────┘
`
└─────────────────────────────────┘`
]);
});

it('parse', () => {
expect(
table.parse(`
┌──────────┬───────────┬──────────┐
│ │ firstName │ lastName │
├──────────┼───────────┼──────────┤
│ daughter │ Emily │ Smith │
├──────────┼───────────┼──────────┤
│ father │ John │ Smith │
├──────────┼───────────┼──────────┤
│ mother │ Jane │ Smith │
└──────────┴───────────┴──────────┘`)
).to.eql(data);
expect(
table.parse(
`
firstName lastName
daughter Emily Smith
father John Smith
mother Jane Smith`,
{
border: {
bodyLeft: '',
bodyJoin: ' ',
bodyRight: ''
}
}
)
).to.eql(data);
expect(
table.parse(`
┌─────┬───────┬───────┬─────────────────┐
│ PID│TTY │TIME │CMD │
├─────┼───────┼───────┼─────────────────┤
│68667│ttys000│0:00.01│login -fp runzisu│
└─────┴───────┴───────┴─────────────────┘`)
).to.eql([
['PID', 'TTY', 'TIME', 'CMD'],
['68667', 'ttys000', '0:00.01', 'login -fp runzisu']
]);
expect(
table.parse(
`
PID TTY TIME CMD
68667 ttys000 0:00.01 login -fp runzisu`,
{
border: {
bodyLeft: '',
bodyJoin: ' ',
bodyRight: ''
}
}
)
).to.eql([
['PID', 'TTY', 'TIME', 'CMD'],
['68667', 'ttys000', '0:00.01', 'login -fp runzisu']
]);
expect(
table.parse(
`
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ ARGS
19132 shell 20 0 2.0G 4.0M 3.0M R 27.7 0.1 0:00.13 top -n 1
11635 shell 20 0 2.0G 1.9M 1.8M S 5.5 0.0 5:15.83 process-tracker --interval 1000`,
{
border: {
bodyLeft: '',
bodyJoin: ' ',
bodyRight: ''
}
}
)
).to.eql([
[
'PID',
'USER',
'PR',
'NI',
'VIRT',
'RES',
'SHR',
'S',
'%CPU',
'%MEM',
'TIME+',
'ARGS'
],
[
'19132',
'shell',
'20',
'0',
'2.0G',
'4.0M',
'3.0M',
'R',
'27.7',
'0.1',
'0:00.13',
'top -n 1'
],
[
'11635',
'shell',
'20',
'0',
'2.0G',
'1.9M',
'1.8M',
'S',
'5.5',
'0.0',
'5:15.83',
'process-tracker --interval 1000'
]
]);
});

0 comments on commit 398bbc6

Please sign in to comment.