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