table.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. 'use strict'
  2. var whitespace = require('is-whitespace-character')
  3. module.exports = table
  4. var tab = '\t'
  5. var lineFeed = '\n'
  6. var space = ' '
  7. var dash = '-'
  8. var colon = ':'
  9. var backslash = '\\'
  10. var verticalBar = '|'
  11. var minColumns = 1
  12. var minRows = 2
  13. var left = 'left'
  14. var center = 'center'
  15. var right = 'right'
  16. function table(eat, value, silent) {
  17. var self = this
  18. var index
  19. var alignments
  20. var alignment
  21. var subvalue
  22. var row
  23. var length
  24. var lines
  25. var queue
  26. var character
  27. var hasDash
  28. var align
  29. var cell
  30. var preamble
  31. var now
  32. var position
  33. var lineCount
  34. var line
  35. var rows
  36. var table
  37. var lineIndex
  38. var pipeIndex
  39. var first
  40. // Exit when not in gfm-mode.
  41. if (!self.options.gfm) {
  42. return
  43. }
  44. // Get the rows.
  45. // Detecting tables soon is hard, so there are some checks for performance
  46. // here, such as the minimum number of rows, and allowed characters in the
  47. // alignment row.
  48. index = 0
  49. lineCount = 0
  50. length = value.length + 1
  51. lines = []
  52. while (index < length) {
  53. lineIndex = value.indexOf(lineFeed, index)
  54. pipeIndex = value.indexOf(verticalBar, index + 1)
  55. if (lineIndex === -1) {
  56. lineIndex = value.length
  57. }
  58. if (pipeIndex === -1 || pipeIndex > lineIndex) {
  59. if (lineCount < minRows) {
  60. return
  61. }
  62. break
  63. }
  64. lines.push(value.slice(index, lineIndex))
  65. lineCount++
  66. index = lineIndex + 1
  67. }
  68. // Parse the alignment row.
  69. subvalue = lines.join(lineFeed)
  70. alignments = lines.splice(1, 1)[0] || []
  71. index = 0
  72. length = alignments.length
  73. lineCount--
  74. alignment = false
  75. align = []
  76. while (index < length) {
  77. character = alignments.charAt(index)
  78. if (character === verticalBar) {
  79. hasDash = null
  80. if (alignment === false) {
  81. if (first === false) {
  82. return
  83. }
  84. } else {
  85. align.push(alignment)
  86. alignment = false
  87. }
  88. first = false
  89. } else if (character === dash) {
  90. hasDash = true
  91. alignment = alignment || null
  92. } else if (character === colon) {
  93. if (alignment === left) {
  94. alignment = center
  95. } else if (hasDash && alignment === null) {
  96. alignment = right
  97. } else {
  98. alignment = left
  99. }
  100. } else if (!whitespace(character)) {
  101. return
  102. }
  103. index++
  104. }
  105. if (alignment !== false) {
  106. align.push(alignment)
  107. }
  108. // Exit when without enough columns.
  109. if (align.length < minColumns) {
  110. return
  111. }
  112. /* istanbul ignore if - never used (yet) */
  113. if (silent) {
  114. return true
  115. }
  116. // Parse the rows.
  117. position = -1
  118. rows = []
  119. table = eat(subvalue).reset({type: 'table', align: align, children: rows})
  120. while (++position < lineCount) {
  121. line = lines[position]
  122. row = {type: 'tableRow', children: []}
  123. // Eat a newline character when this is not the first row.
  124. if (position) {
  125. eat(lineFeed)
  126. }
  127. // Eat the row.
  128. eat(line).reset(row, table)
  129. length = line.length + 1
  130. index = 0
  131. queue = ''
  132. cell = ''
  133. preamble = true
  134. while (index < length) {
  135. character = line.charAt(index)
  136. if (character === tab || character === space) {
  137. if (cell) {
  138. queue += character
  139. } else {
  140. eat(character)
  141. }
  142. index++
  143. continue
  144. }
  145. if (character === '' || character === verticalBar) {
  146. if (preamble) {
  147. eat(character)
  148. } else {
  149. if ((cell || character) && !preamble) {
  150. subvalue = cell
  151. if (queue.length > 1) {
  152. if (character) {
  153. subvalue += queue.slice(0, -1)
  154. queue = queue.charAt(queue.length - 1)
  155. } else {
  156. subvalue += queue
  157. queue = ''
  158. }
  159. }
  160. now = eat.now()
  161. eat(subvalue)(
  162. {type: 'tableCell', children: self.tokenizeInline(cell, now)},
  163. row
  164. )
  165. }
  166. eat(queue + character)
  167. queue = ''
  168. cell = ''
  169. }
  170. } else {
  171. if (queue) {
  172. cell += queue
  173. queue = ''
  174. }
  175. cell += character
  176. if (character === backslash && index !== length - 2) {
  177. cell += line.charAt(index + 1)
  178. index++
  179. }
  180. }
  181. preamble = false
  182. index++
  183. }
  184. // Eat the alignment row.
  185. if (!position) {
  186. eat(lineFeed + alignments)
  187. }
  188. }
  189. return table
  190. }