mdtabeditor/deserialize_table.mjs

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};