3 module.exports = markdownTable
6 var lastDotRe = /\.[^.]*$/
21 // Create a table from a matrix of strings.
22 function markdownTable(table, options) {
23 var settings = options || {}
24 var delimiter = settings.delimiter
25 var start = settings.start
26 var end = settings.end
27 var alignment = settings.align
28 var calculateStringLength = settings.stringLength || lengthNoop
31 var rowLength = table.length
46 alignment = alignment ? alignment.concat() : []
48 if (delimiter === null || delimiter === undefined) {
49 delimiter = space + verticalBar + space
52 if (start === null || start === undefined) {
53 start = verticalBar + space
56 if (end === null || end === undefined) {
57 end = space + verticalBar
60 while (++rowIndex < rowLength) {
65 if (row.length > cellCount) {
66 cellCount = row.length
69 while (++index < cellCount) {
70 position = row[index] ? dotindex(row[index]) : null
73 sizes[index] = minCellSize
76 if (position > sizes[index]) {
77 sizes[index] = position
82 if (typeof alignment === 'string') {
83 alignment = pad(cellCount, alignment).split('')
86 // Make sure only valid alignments are used.
89 while (++index < cellCount) {
90 align = alignment[index]
92 if (typeof align === 'string') {
93 align = align.charAt(0).toLowerCase()
97 align !== lowercaseL &&
98 align !== lowercaseR &&
99 align !== lowercaseC &&
105 alignment[index] = align
111 while (++rowIndex < rowLength) {
112 row = table[rowIndex]
117 while (++index < cellCount) {
120 value = stringify(value)
122 if (alignment[index] === dot) {
123 position = dotindex(value)
127 (dotRe.test(value) ? 0 : 1) -
128 (calculateStringLength(value) - position)
130 cells[index] = value + pad(size - 1)
136 rows[rowIndex] = cells
142 while (++rowIndex < rowLength) {
143 cells = rows[rowIndex]
147 while (++index < cellCount) {
151 sizes[index] = minCellSize
154 size = calculateStringLength(value)
156 if (size > sizes[index]) {
164 while (++rowIndex < rowLength) {
165 cells = rows[rowIndex]
169 if (settings.pad !== false) {
170 while (++index < cellCount) {
173 position = sizes[index] - (calculateStringLength(value) || 0)
174 spacing = pad(position)
176 if (alignment[index] === lowercaseR || alignment[index] === dot) {
177 value = spacing + value
178 } else if (alignment[index] === lowercaseC) {
181 if (position % 1 === 0) {
185 before = position + 0.5
186 after = position - 0.5
189 value = pad(before) + value + pad(after)
198 rows[rowIndex] = cells.join(delimiter)
201 if (settings.rule !== false) {
205 while (++index < cellCount) {
206 // When `pad` is false, make the rule the same size as the first row.
207 if (settings.pad === false) {
208 value = table[0][index]
209 spacing = calculateStringLength(stringify(value))
210 spacing = spacing > minCellSize ? spacing : minCellSize
212 spacing = sizes[index]
215 align = alignment[index]
217 // When `align` is left, don't add colons.
218 value = align === lowercaseR || align === '' ? dash : colon
219 value += pad(spacing - 2, dash)
220 value += align !== lowercaseL && align !== '' ? colon : dash
225 rows.splice(1, 0, rule.join(delimiter))
228 return start + rows.join(end + lineFeed + start) + end
231 function stringify(value) {
232 return value === null || value === undefined ? '' : String(value)
235 // Get the length of `value`.
236 function lengthNoop(value) {
237 return String(value).length
240 // Get a string consisting of `length` `character`s.
241 function pad(length, character) {
242 return new Array(length + 1).join(character || space)
245 // Get the position of the last dot in `value`.
246 function dotindex(value) {
247 var match = lastDotRe.exec(value)
249 return match ? match.index + 1 : value.length