You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

250 lines
5.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

'use strict'
var repeat = require('repeat-string')
module.exports = markdownTable
var trailingWhitespace = / +$/
// Characters.
var space = ' '
var lineFeed = '\n'
var dash = '-'
var colon = ':'
var verticalBar = '|'
var x = 0
var C = 67
var L = 76
var R = 82
var c = 99
var l = 108
var r = 114
// Create a table from a matrix of strings.
function markdownTable(table, options) {
var settings = options || {}
var padding = settings.padding !== false
var start = settings.delimiterStart !== false
var end = settings.delimiterEnd !== false
var align = (settings.align || []).concat()
var alignDelimiters = settings.alignDelimiters !== false
var alignments = []
var stringLength = settings.stringLength || defaultStringLength
var rowIndex = -1
var rowLength = table.length
var cellMatrix = []
var sizeMatrix = []
var row = []
var sizes = []
var longestCellByColumn = []
var mostCellsPerRow = 0
var cells
var columnIndex
var columnLength
var largest
var size
var cell
var lines
var line
var before
var after
var code
// This is a superfluous loop if we dont align delimiters, but otherwise wed
// do superfluous work when aligning, so optimize for aligning.
while (++rowIndex < rowLength) {
cells = table[rowIndex]
columnIndex = -1
columnLength = cells.length
row = []
sizes = []
if (columnLength > mostCellsPerRow) {
mostCellsPerRow = columnLength
}
while (++columnIndex < columnLength) {
cell = serialize(cells[columnIndex])
if (alignDelimiters === true) {
size = stringLength(cell)
sizes[columnIndex] = size
largest = longestCellByColumn[columnIndex]
if (largest === undefined || size > largest) {
longestCellByColumn[columnIndex] = size
}
}
row.push(cell)
}
cellMatrix[rowIndex] = row
sizeMatrix[rowIndex] = sizes
}
// Figure out which alignments to use.
columnIndex = -1
columnLength = mostCellsPerRow
if (typeof align === 'object' && 'length' in align) {
while (++columnIndex < columnLength) {
alignments[columnIndex] = toAlignment(align[columnIndex])
}
} else {
code = toAlignment(align)
while (++columnIndex < columnLength) {
alignments[columnIndex] = code
}
}
// Inject the alignment row.
columnIndex = -1
columnLength = mostCellsPerRow
row = []
sizes = []
while (++columnIndex < columnLength) {
code = alignments[columnIndex]
before = ''
after = ''
if (code === l) {
before = colon
} else if (code === r) {
after = colon
} else if (code === c) {
before = colon
after = colon
}
// There *must* be at least one hyphen-minus in each alignment cell.
size = alignDelimiters
? Math.max(
1,
longestCellByColumn[columnIndex] - before.length - after.length
)
: 1
cell = before + repeat(dash, size) + after
if (alignDelimiters === true) {
size = before.length + size + after.length
if (size > longestCellByColumn[columnIndex]) {
longestCellByColumn[columnIndex] = size
}
sizes[columnIndex] = size
}
row[columnIndex] = cell
}
// Inject the alignment row.
cellMatrix.splice(1, 0, row)
sizeMatrix.splice(1, 0, sizes)
rowIndex = -1
rowLength = cellMatrix.length
lines = []
while (++rowIndex < rowLength) {
row = cellMatrix[rowIndex]
sizes = sizeMatrix[rowIndex]
columnIndex = -1
columnLength = mostCellsPerRow
line = []
while (++columnIndex < columnLength) {
cell = row[columnIndex] || ''
before = ''
after = ''
if (alignDelimiters === true) {
size = longestCellByColumn[columnIndex] - (sizes[columnIndex] || 0)
code = alignments[columnIndex]
if (code === r) {
before = repeat(space, size)
} else if (code === c) {
if (size % 2 === 0) {
before = repeat(space, size / 2)
after = before
} else {
before = repeat(space, size / 2 + 0.5)
after = repeat(space, size / 2 - 0.5)
}
} else {
after = repeat(space, size)
}
}
if (start === true && columnIndex === 0) {
line.push(verticalBar)
}
if (
padding === true &&
// Dont add the opening space if were not aligning and the cell is
// empty: there will be a closing space.
!(alignDelimiters === false && cell === '') &&
(start === true || columnIndex !== 0)
) {
line.push(space)
}
if (alignDelimiters === true) {
line.push(before)
}
line.push(cell)
if (alignDelimiters === true) {
line.push(after)
}
if (padding === true) {
line.push(space)
}
if (end === true || columnIndex !== columnLength - 1) {
line.push(verticalBar)
}
}
line = line.join('')
if (end === false) {
line = line.replace(trailingWhitespace, '')
}
lines.push(line)
}
return lines.join(lineFeed)
}
function serialize(value) {
return value === null || value === undefined ? '' : String(value)
}
function defaultStringLength(value) {
return value.length
}
function toAlignment(value) {
var code = typeof value === 'string' ? value.charCodeAt(0) : x
return code === L || code === l
? l
: code === R || code === r
? r
: code === C || code === c
? c
: x
}