--- /dev/null
+'use strict';
+
+var whitespace = require('is-whitespace-character');
+
+module.exports = table;
+
+var C_BACKSLASH = '\\';
+var C_TICK = '`';
+var C_DASH = '-';
+var C_PIPE = '|';
+var C_COLON = ':';
+var C_SPACE = ' ';
+var C_NEWLINE = '\n';
+var C_TAB = '\t';
+
+var MIN_TABLE_COLUMNS = 1;
+var MIN_TABLE_ROWS = 2;
+
+var TABLE_ALIGN_LEFT = 'left';
+var TABLE_ALIGN_CENTER = 'center';
+var TABLE_ALIGN_RIGHT = 'right';
+var TABLE_ALIGN_NONE = null;
+
+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 count;
+ var opening;
+ 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(C_NEWLINE, index);
+ pipeIndex = value.indexOf(C_PIPE, index + 1);
+
+ if (lineIndex === -1) {
+ lineIndex = value.length;
+ }
+
+ if (pipeIndex === -1 || pipeIndex > lineIndex) {
+ if (lineCount < MIN_TABLE_ROWS) {
+ return;
+ }
+
+ break;
+ }
+
+ lines.push(value.slice(index, lineIndex));
+ lineCount++;
+ index = lineIndex + 1;
+ }
+
+ /* Parse the alignment row. */
+ subvalue = lines.join(C_NEWLINE);
+ alignments = lines.splice(1, 1)[0] || [];
+ index = 0;
+ length = alignments.length;
+ lineCount--;
+ alignment = false;
+ align = [];
+
+ while (index < length) {
+ character = alignments.charAt(index);
+
+ if (character === C_PIPE) {
+ hasDash = null;
+
+ if (alignment === false) {
+ if (first === false) {
+ return;
+ }
+ } else {
+ align.push(alignment);
+ alignment = false;
+ }
+
+ first = false;
+ } else if (character === C_DASH) {
+ hasDash = true;
+ alignment = alignment || TABLE_ALIGN_NONE;
+ } else if (character === C_COLON) {
+ if (alignment === TABLE_ALIGN_LEFT) {
+ alignment = TABLE_ALIGN_CENTER;
+ } else if (hasDash && alignment === TABLE_ALIGN_NONE) {
+ alignment = TABLE_ALIGN_RIGHT;
+ } else {
+ alignment = TABLE_ALIGN_LEFT;
+ }
+ } else if (!whitespace(character)) {
+ return;
+ }
+
+ index++;
+ }
+
+ if (alignment !== false) {
+ align.push(alignment);
+ }
+
+ /* Exit when without enough columns. */
+ if (align.length < MIN_TABLE_COLUMNS) {
+ 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(C_NEWLINE);
+ }
+
+ /* Eat the row. */
+ eat(line).reset(row, table);
+
+ length = line.length + 1;
+ index = 0;
+ queue = '';
+ cell = '';
+ preamble = true;
+ count = null;
+ opening = null;
+
+ while (index < length) {
+ character = line.charAt(index);
+
+ if (character === C_TAB || character === C_SPACE) {
+ if (cell) {
+ queue += character;
+ } else {
+ eat(character);
+ }
+
+ index++;
+ continue;
+ }
+
+ if (character === '' || character === C_PIPE) {
+ if (preamble) {
+ eat(character);
+ } else {
+ if (character && opening) {
+ queue += character;
+ index++;
+ continue;
+ }
+
+ if ((cell || character) && !preamble) {
+ subvalue = cell;
+
+ if (queue.length > 1) {
+ if (character) {
+ subvalue += queue.slice(0, queue.length - 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 === C_BACKSLASH && index !== length - 2) {
+ cell += line.charAt(index + 1);
+ index++;
+ }
+
+ if (character === C_TICK) {
+ count = 1;
+
+ while (line.charAt(index + 1) === character) {
+ cell += character;
+ index++;
+ count++;
+ }
+
+ if (!opening) {
+ opening = count;
+ } else if (count >= opening) {
+ opening = 0;
+ }
+ }
+ }
+
+ preamble = false;
+ index++;
+ }
+
+ /* Eat the alignment row. */
+ if (!position) {
+ eat(C_NEWLINE + alignments);
+ }
+ }
+
+ return table;
+}