'use strict' module.exports = markdownTable var dotRe = /\./ var lastDotRe = /\.[^.]*$/ // Characters. var space = ' ' var lineFeed = '\n' var dash = '-' var dot = '.' var colon = ':' var lowercaseC = 'c' var lowercaseL = 'l' var lowercaseR = 'r' var verticalBar = '|' var minCellSize = 3 // Create a table from a matrix of strings. function markdownTable(table, options) { var settings = options || {} var delimiter = settings.delimiter var start = settings.start var end = settings.end var alignment = settings.align var calculateStringLength = settings.stringLength || lengthNoop var cellCount = 0 var rowIndex = -1 var rowLength = table.length var sizes = [] var align var rule var rows var row var cells var index var position var size var value var spacing var before var after alignment = alignment ? alignment.concat() : [] if (delimiter === null || delimiter === undefined) { delimiter = space + verticalBar + space } if (start === null || start === undefined) { start = verticalBar + space } if (end === null || end === undefined) { end = space + verticalBar } while (++rowIndex < rowLength) { row = table[rowIndex] index = -1 if (row.length > cellCount) { cellCount = row.length } while (++index < cellCount) { position = row[index] ? dotindex(row[index]) : null if (!sizes[index]) { sizes[index] = minCellSize } if (position > sizes[index]) { sizes[index] = position } } } if (typeof alignment === 'string') { alignment = pad(cellCount, alignment).split('') } // Make sure only valid alignments are used. index = -1 while (++index < cellCount) { align = alignment[index] if (typeof align === 'string') { align = align.charAt(0).toLowerCase() } if ( align !== lowercaseL && align !== lowercaseR && align !== lowercaseC && align !== dot ) { align = '' } alignment[index] = align } rowIndex = -1 rows = [] while (++rowIndex < rowLength) { row = table[rowIndex] index = -1 cells = [] while (++index < cellCount) { value = row[index] value = stringify(value) if (alignment[index] === dot) { position = dotindex(value) size = sizes[index] + (dotRe.test(value) ? 0 : 1) - (calculateStringLength(value) - position) cells[index] = value + pad(size - 1) } else { cells[index] = value } } rows[rowIndex] = cells } sizes = [] rowIndex = -1 while (++rowIndex < rowLength) { cells = rows[rowIndex] index = -1 while (++index < cellCount) { value = cells[index] if (!sizes[index]) { sizes[index] = minCellSize } size = calculateStringLength(value) if (size > sizes[index]) { sizes[index] = size } } } rowIndex = -1 while (++rowIndex < rowLength) { cells = rows[rowIndex] index = -1 if (settings.pad !== false) { while (++index < cellCount) { value = cells[index] position = sizes[index] - (calculateStringLength(value) || 0) spacing = pad(position) if (alignment[index] === lowercaseR || alignment[index] === dot) { value = spacing + value } else if (alignment[index] === lowercaseC) { position /= 2 if (position % 1 === 0) { before = position after = position } else { before = position + 0.5 after = position - 0.5 } value = pad(before) + value + pad(after) } else { value += spacing } cells[index] = value } } rows[rowIndex] = cells.join(delimiter) } if (settings.rule !== false) { index = -1 rule = [] while (++index < cellCount) { // When `pad` is false, make the rule the same size as the first row. if (settings.pad === false) { value = table[0][index] spacing = calculateStringLength(stringify(value)) spacing = spacing > minCellSize ? spacing : minCellSize } else { spacing = sizes[index] } align = alignment[index] // When `align` is left, don't add colons. value = align === lowercaseR || align === '' ? dash : colon value += pad(spacing - 2, dash) value += align !== lowercaseL && align !== '' ? colon : dash rule[index] = value } rows.splice(1, 0, rule.join(delimiter)) } return start + rows.join(end + lineFeed + start) + end } function stringify(value) { return value === null || value === undefined ? '' : String(value) } // Get the length of `value`. function lengthNoop(value) { return String(value).length } // Get a string consisting of `length` `character`s. function pad(length, character) { return new Array(length + 1).join(character || space) } // Get the position of the last dot in `value`. function dotindex(value) { var match = lastDotRe.exec(value) return match ? match.index + 1 : value.length }