127 lines
3.2 KiB
JavaScript
127 lines
3.2 KiB
JavaScript
/*
|
|
* line: string, must be trimmed of whitespace beforehand
|
|
* tableItems: int | null, result output will be padded or trimmed to it if specified
|
|
*
|
|
* Returns an array of strings
|
|
*/
|
|
function splitByPipe(line, tableItems = null) {
|
|
let res = [];
|
|
let item = "";
|
|
let consecutiveBackslashes = 0;
|
|
|
|
if (line.startsWith("|")) {
|
|
line = line.substring(1);
|
|
}
|
|
|
|
for (let char of line) {
|
|
if (char === "\\") {
|
|
item += "\\";
|
|
consecutiveBackslashes++;
|
|
} else if (char === "|" && consecutiveBackslashes % 2 === 1) {
|
|
item = item.substring(0, item.length - 1) + "|";
|
|
consecutiveBackslashes = 0;
|
|
} else if (char === "|" && consecutiveBackslashes % 2 === 0) {
|
|
item = item.trim();
|
|
res.push(item);
|
|
|
|
item = "";
|
|
consecutiveBackslashes = 0;
|
|
} else {
|
|
item += char;
|
|
consecutiveBackslashes = 0;
|
|
}
|
|
}
|
|
item = item.trim();
|
|
if (item.length !== 0) {
|
|
res.push(item);
|
|
}
|
|
|
|
while (tableItems !== null && res.length < tableItems) {
|
|
res.push("");
|
|
}
|
|
while (tableItems !== null && res.length > tableItems) {
|
|
res.pop();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* line: string, must be trimmed of whitespace beforehand
|
|
* headerRow: array of strings
|
|
*
|
|
* Returns an array of objects, which has the following keys:
|
|
* - text: string
|
|
* - leftAligned: boolean
|
|
* - rightAligned: boolean
|
|
*/
|
|
function parseDelimiterRow(line, headerRow) {
|
|
let res = [];
|
|
let delimiterRow = splitByPipe(line);
|
|
|
|
if (delimiterRow.length !== headerRow.length) {
|
|
throw new Error(`delimiter row is not as long as the header row (${delimiterRow.length} !== ${headerRow.length})`);
|
|
}
|
|
|
|
for (let i = 0; i < headerRow.length; i++) {
|
|
let header = headerRow[i];
|
|
let delimiter = delimiterRow[i];
|
|
let match = delimiter.match(/^(:)?-+(:)?$/);
|
|
|
|
if (match === null) {
|
|
throw new Error(`invalid delimiter row (index: ${i}): ${delimiter}`);
|
|
}
|
|
res.push({
|
|
text: header,
|
|
leftAligned: match[1] === ":",
|
|
rightAligned: match[2] === ":"
|
|
});
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* lines: array of strings, each item must be trimmed of whitespace beforehand
|
|
*
|
|
* See parseDelimiterRow() for the return type
|
|
*/
|
|
function parseHeader(lines) {
|
|
if (lines.length < 2) {
|
|
throw new Error(`input must be at least 2 lines long (${lines.length} < 2)`);
|
|
}
|
|
|
|
let headerRow = splitByPipe(lines[0]);
|
|
if (headerRow.length === 0) {
|
|
throw new Error("header row must have at least one item");
|
|
}
|
|
|
|
return parseDelimiterRow(lines[1], headerRow);
|
|
}
|
|
|
|
/*
|
|
* input: string
|
|
*
|
|
* Returns an object with the following keys:
|
|
* - columns: See parseHeader() for the first item
|
|
* - rows: array of an array of strings
|
|
*/
|
|
function deserializeTable(input) {
|
|
let lines = [];
|
|
let rows = [];
|
|
|
|
for (let line of input.trim().split("\n")) {
|
|
lines.push(line.trim());
|
|
}
|
|
|
|
let columns = parseHeader(lines);
|
|
for (let i = 2; i < lines.length; i++) {
|
|
rows.push(splitByPipe(lines[i], columns.length));
|
|
}
|
|
|
|
return {columns, rows};
|
|
}
|
|
|
|
|
|
|
|
export {deserializeTable};
|