All files Table.js

88.79% Statements 95/107
56.25% Branches 18/32
95.83% Functions 23/24
90.48% Lines 95/105
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200  1x 1x 1x 1x 1x 1x 1x     1x     17x 17x 17x 17x 17x 17x         1x 10x 10x 10x 10x                   10x   10x     1x 17x       17x 3x 3x 3x       17x 16x       17x     17x 17x 25x 25x 25x         17x     1x 3x 3x 3x     1x 16x 16x 20x 20x 20x   16x     1x 7x 7x 7x     7x         7x 8x       7x     7x 7x 7x 7x         7x     1x 7x 7x 8x   7x 7x 12x   1x 3x     11x       7x     1x 7x     7x 7x     7x 22x 22x 38x 35x 35x   38x         7x 22x 22x 38x 3x 3x 3x 3x                       38x         1x 9x             14x     14x        
// Import
var range = require('lodash.range')
var repeat = require('lodash.repeat')
var re = require('./regex')
var Row = require('./Row')
var MultilineRow = require('./MultilineRow')
var Colgroup = require('./Colgroup')
var TBody = require('./TBody')
 
// Export
module.exports = Table
 
function Table () {
  this.id = undefined
  this.caption = undefined
  this.headers = []
  this.colgroup = new Colgroup()
  this.tbodies = []
  this.styles = {
    border: true
  }
}
 
Table.prototype.parse = function (src, offset) {
  this.rawTable = src
  var match = re.wholeTable.exec(src)
  Iif (!match) return false
  var infos = {
    offset: 0,
    offsetEnd: match[0].length,
    raw: match[0],
    caption: match[1],
    headers: match[2],
    columns: match[3],
    rows: match[4]
  }
 
  this.handleParseResult(infos)
 
  return infos
}
 
Table.prototype.handleParseResult = function (pResult) {
  var self = this
  var match
 
  // Read captions and id
  if (pResult.caption) {
    match = this._handleCaption(pResult.caption)
    this.id = match[1] ? match[2].trim() : undefined
    this.caption = match[1] ? match[1] : match[2]
  }
 
  // Read headers
  if (pResult.headers) {
    this.headers = this._handleHeaders(pResult.headers)
  }
 
  // Read columns
  this.colgroup.parse(pResult.columns)
 
  // Read rows
  Eif (pResult.rows) {
    pResult.rows.trim().split(/\n[\s.]*\n/g).forEach(function (body) {
      var tbody = new TBody()
      tbody.parse(body)
      self.tbodies.push(tbody)
    })
  }
 
  // Extract style information:
  this.styles.border = /^|/.test(pResult.columns)
}
 
Table.prototype._handleCaption = function (caption) {
  var reg = /^(?:\[([^\]]*?)\])?(?:\[([^\]]*?)\])[ \t]*/
  var match = reg.exec(caption)
  return match
}
 
Table.prototype._handleHeaders = function (headers) {
  var result = []
  headers.trim().split('\n').forEach(function (line) {
    var row = new Row()
    row.parse(line)
    result.push(row)
  })
  return result
}
 
Table.prototype.toMarkdown = function () {
  var self = this
  self.normalize()
  var out = []
 
  // Caption and table id
  Iif (self.caption) {
    out.push('[' + self.caption + ']' + (self.id ? '[' + self.id + ']' : ''))
  }
 
  // Headers
  self.headers.forEach(function (row) {
    out.push(row.toMarkdown(self.colgroup))
  })
 
  // column alignment
  out.push(self.colgroup.toMarkdown())
 
  // Headers
  var countTbody = self.tbodies.length
  self.tbodies.forEach(function (tbody, i) {
    out.push(tbody.toMarkdown(self.colgroup))
    Iif ((countTbody - 1) !== i) {
      out.push(repeat(' ', self.colgroup.getFullFormatedSize()))
    }
  })
 
  return out.join('\n')
}
 
Table.prototype._getAllRow = function () {
  var allRows = []
  this.headers.forEach(function (row) {
    allRows.push(row)
  })
  this.tbodies.forEach(function (tbody) {
    tbody.rows.forEach(function (row) {
      if (row instanceof MultilineRow) {
        // TODO: put this in TBody
        row.rows.forEach(function (row) {
          allRows.push(row)
        })
      } else {
        allRows.push(row)
      }
    })
  })
  return allRows
}
 
Table.prototype.normalize = function () {
  var self = this
 
  // Normalize columns size
  var allRows = self._getAllRow()
  var colgroup = self.colgroup
 
  // First pass normal cell
  allRows.forEach(function (row) {
    var index = 0
    row.cells.forEach(function (cell) {
      if (cell.colspan === 1) {
        var sizeNeeded = cell.getContentSize()
        self.colgroup.upSizeTo(index, sizeNeeded)
      }
      index += cell.colspan
    })
  })
 
  // Second pass (to adjust colspan cell)
  allRows.forEach(function (row) {
    var index = 0
    row.cells.forEach(function (cell) {
      if (cell.colspan > 1) {
        var sizeNeeded = cell.getContentSize()
        var currentSize = colgroup.getFormatedSizeAt(index, cell.colspan)
        var remainSizeNeeded = sizeNeeded - currentSize
        Iif (remainSizeNeeded > 0) {
          var sharedSize = Math.ceil(remainSizeNeeded / cell.colspan)
          range(index, index + cell.colspan).forEach(function (index) {
            if (remainSizeNeeded <= 0) return
            var cur = self.colgroup.getColumnAt(index).getSize()
            var add = (remainSizeNeeded < sharedSize ? remainSizeNeeded : sharedSize)
            var upto = cur + add
            self.colgroup.upSizeTo(index, upto)
            remainSizeNeeded -= add
          })
        }
      }
      index += cell.colspan
    })
  })
}
 
Table.prototype.getInfos = function () {
  return {
    id: this.id,
    caption: this.caption,
    headers: this.headers ? this.headers.length : 0,
    columns: this.colgroup.columns.length,
    bodies: this.tbodies.length,
    rows: this.tbodies.reduce(function (memo, tbody) {
      return memo + tbody.rows.length
    }, 0),
    lines: this.tbodies.reduce(function (memo, tbody) {
      return memo + tbody.getInfos().lines
    }, 0)
  }
}