@mapbox/jsxtreme-markdown
Version:
Transform Markdown into JSX or React component modules
233 lines (190 loc) • 4.6 kB
JavaScript
'use strict';
var whitespace = require('is-whitespace-character');
module.exports = table;
var tab = '\t';
var lineFeed = '\n';
var space = ' ';
var dash = '-';
var colon = ':';
var backslash = '\\';
var verticalBar = '|';
var minColumns = 1;
var minRows = 2;
var left = 'left';
var center = 'center';
var right = 'right';
function table(eat, value, silent) {
var self = this;
var index;
var alignments;
var alignment;
var subvalue;
var row;
var length;
var lines;
var queue;
var character;
var hasDash;
var align;
var cell;
var preamble;
var now;
var position;
var lineCount;
var line;
var rows;
var table;
var lineIndex;
var pipeIndex;
var first;
// Exit when not in gfm-mode.
if (!self.options.gfm) {
return;
}
// Get the rows.
// Detecting tables soon is hard, so there are some checks for performance
// here, such as the minimum number of rows, and allowed characters in the
// alignment row.
index = 0;
lineCount = 0;
length = value.length + 1;
lines = [];
while (index < length) {
lineIndex = value.indexOf(lineFeed, index);
pipeIndex = value.indexOf(verticalBar, index + 1);
if (lineIndex === -1) {
lineIndex = value.length;
}
if (pipeIndex === -1 || pipeIndex > lineIndex) {
if (lineCount < minRows) {
return;
}
break;
}
lines.push(value.slice(index, lineIndex));
lineCount++;
index = lineIndex + 1;
}
// Parse the alignment row.
subvalue = lines.join(lineFeed);
alignments = lines.splice(1, 1)[0] || [];
index = 0;
length = alignments.length;
lineCount--;
alignment = false;
align = [];
while (index < length) {
character = alignments.charAt(index);
if (character === verticalBar) {
hasDash = null;
if (alignment === false) {
if (first === false) {
return;
}
} else {
align.push(alignment);
alignment = false;
}
first = false;
} else if (character === dash) {
hasDash = true;
alignment = alignment || null;
} else if (character === colon) {
if (alignment === left) {
alignment = center;
} else if (hasDash && alignment === null) {
alignment = right;
} else {
alignment = left;
}
} else if (!whitespace(character)) {
return;
}
index++;
}
if (alignment !== false) {
align.push(alignment);
}
// Exit when without enough columns.
if (align.length < minColumns) {
return;
}
/* istanbul ignore if - never used (yet) */
if (silent) {
return true;
}
// Parse the rows.
position = -1;
rows = [];
table = eat(subvalue).reset({ type: 'table', align: align, children: rows });
while (++position < lineCount) {
line = lines[position];
row = { type: 'tableRow', children: [] };
// Eat a newline character when this is not the first row.
if (position) {
eat(lineFeed);
}
// Eat the row.
eat(line).reset(row, table);
length = line.length + 1;
index = 0;
queue = '';
cell = '';
preamble = true;
while (index < length) {
character = line.charAt(index);
if (character === tab || character === space) {
if (cell) {
queue += character;
} else {
eat(character);
}
index++;
continue;
}
if (character === '' || character === verticalBar) {
if (preamble) {
eat(character);
} else {
if ((cell || character) && !preamble) {
subvalue = cell;
if (queue.length > 1) {
if (character) {
subvalue += queue.slice(0, -1);
queue = queue.charAt(queue.length - 1);
} else {
subvalue += queue;
queue = '';
}
}
now = eat.now();
eat(subvalue)(
{ type: 'tableCell', children: self.tokenizeInline(cell, now) },
row
);
}
eat(queue + character);
queue = '';
cell = '';
}
} else {
if (queue) {
cell += queue;
queue = '';
}
cell += character;
if (character === backslash && index !== length - 2) {
cell += line.charAt(index + 1);
index++;
}
}
preamble = false;
index++;
}
// Eat the alignment row.
if (!position) {
eat(lineFeed + alignments);
}
}
return table;
}