UNPKG

@mapbox/jsxtreme-markdown

Version:
233 lines (190 loc) 4.6 kB
'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; }