--- /dev/null
+'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
+}