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