UNPKG

6.22 kBJavaScriptView Raw
1module.exports = Table
2
3Table.string = function (val) {
4 if (val === undefined) return ''
5 return String(val)
6}
7
8Table.Number = function (digits) {
9 return function (val, width) {
10 if (val === undefined) return ''
11 if (typeof val != 'number')
12 throw new Error(String(val) + ' is not a number')
13 var s = digits == null ? String(val) : val.toFixed(digits).toString()
14 return Table.padLeft(s, width)
15 }
16}
17
18Table.RightPadder = function (char) {
19 char = char || ' '
20 return function (val, length) {
21 var s = String(val)
22 var l = s.length
23 for (var i = 0; i < length - l; i++) {
24 s += char
25 }
26 return s
27 }
28}
29
30Table.LeftPadder = function (char) {
31 char = char || ' '
32 return function (val, length) {
33 var ret = ''
34 var s = String(val)
35 for (var i = 0; i < length - s.length; i++) {
36 ret += char
37 }
38 ret += s
39 return ret
40 }
41}
42
43Table.padLeft = Table.LeftPadder()
44
45Table.printArray = function (arr, format, cb) {
46 format = typeof format == 'function' ? format : Formatter(format)
47 cb = cb || function (t) {
48 return t.toString()
49 }
50
51 var t = new Table
52 var cell = t.cell.bind(t)
53
54 arr.forEach(function (obj) {
55 format(obj, cell)
56 t.newRow()
57 })
58 return cb(t)
59}
60
61Table.printObj = function (obj, format, cb) {
62 format = typeof format == 'function' ? format : Formatter(format)
63 cb = cb || function (t) {
64 return t.printTransposed(' : ')
65 }
66
67 var t = new Table
68 format(obj, t.cell.bind(t))
69 t.newRow()
70 return cb(t)
71}
72
73function Formatter (opts) {
74 opts = opts || {}
75 return function (obj, cell) {
76 for (var key in obj) {
77 if (!obj.hasOwnProperty(key)) continue
78 var o = opts[key]
79 cell(
80 (o && o.name) || key,
81 obj[key],
82 o && o.printer,
83 o && o.width
84 )
85 }
86 }
87}
88
89
90Table.Row = Row
91function Row () {
92 Object.defineProperties(this, {
93 __printers: {
94 value: {},
95 enumerable: false
96 },
97 __cell: {
98 value: function (col, val, printer) {
99 this[col] = val
100 this.__printers[col] = printer
101 },
102 enumerable: false
103 }
104 })
105}
106
107
108Table.print = print
109function print (rows, columns, shift) {
110 var padSpaces = Table.RightPadder()
111 var widths = {}
112
113 function setWidth (col, width) {
114 var isFixed = columns[col].width != null
115 if (isFixed) {
116 widths[col] = columns[col].width
117 } else {
118 if (widths[col] > width) return
119 widths[col] = width
120 }
121 }
122
123 function cellPrinter (row, col) {
124 return (row.__printers && row.__printers[col]) || Table.string
125 }
126
127 function calcWidths () {
128 rows.forEach(function (row) {
129 for (var key in columns) {
130 setWidth(key, cellPrinter(row, key).call(row, row[key]).length)
131 }
132 })
133 }
134
135 function printRow (cb) {
136 var s = ''
137 var firstColumn = true
138 for (var key in columns) {
139 if (!firstColumn) s += shift
140 firstColumn = false
141 var width = widths[key]
142 s += printCell(cb(key, width), width)
143 }
144 s += '\n'
145 return s
146 }
147
148 function printCell (s, width) {
149 if (s.length <= width) return padSpaces(s, width)
150 s = s.slice(0, width)
151 if (width > 3) s = s.slice(0, -3).concat('...')
152 return s
153 }
154
155 calcWidths()
156
157 return rows.map(function (row) {
158 return printRow(function (key, width) {
159 return cellPrinter(row, key).call(row, row[key], width)
160 })
161 }).join('')
162
163}
164
165
166function Table () {
167 this.columns = {} /* @api: public */
168 this.rows = [] /* @api: public */
169 this._row = new Row
170}
171
172
173Table.prototype.cell = function (col, val, printer, width) {
174 this._row.__cell(col, val, printer)
175 var c = this.columns[col] || (this.columns[col] = {})
176 if (width != null) c.width = width
177 return this
178}
179
180Table.prototype.newRow = Table.prototype.newLine = function () {
181 this.rows.push(this._row)
182 this._row = new Row
183 return this
184}
185
186Table.prototype.sort = require('./sort')
187
188Table.aggr = require('./aggregations')
189
190Table.prototype.totals = null /* @api: public */
191
192Table.prototype.total = function (col, fn, printer) {
193 fn = fn || Table.aggr.sum
194 printer = printer || fn.printer
195
196 this.totals = this.totals || new Row
197
198 var val
199 var rows = this.rows
200
201 this.totals.__cell(col, null, function (_, width) {
202 if (width != null) return printer(val, width)
203 val = rows.reduce(function (val, row, index) {
204 return fn(val, row[col], index, rows.length)
205 }, null)
206 return printer(val)
207 })
208 return this
209}
210
211Table.prototype.shift = ' '
212
213Table.prototype.print = function () {
214 return print(this.rows, this.columns, this.shift)
215}
216
217Table.prototype.printTransposed = function (delimeter) {
218 var t = new Table
219 if (delimeter) t.shift = delimeter
220
221 function Printer (row, key) {
222 var p = row.__printers && row.__printers[key]
223 if (p) return function (val) {
224 return p(val)
225 }
226 }
227
228 for (var key in this.columns) {
229 t.cell('h', key)
230 this.rows.forEach(function (row, index) {
231 t.cell('f' + index, row[key], Printer(row, key))
232 })
233 t.newRow()
234 }
235 return t.print()
236}
237
238Table.prototype.toString = function () {
239 var padWithDashs = Table.RightPadder('-')
240 var delimeter = this.createRow(function () {
241 return ['', padWithDashs]
242 })
243 var head = this.createRow(function (key) {
244 return [key]
245 })
246 var rows = [head, delimeter].concat(this.rows)
247 if (this.totals) {
248 rows = rows.concat([delimeter, this.totals])
249 }
250 return print(rows, this.columns, this.shift)
251}
252
253Table.prototype.createRow = function (cb) {
254 var row = new Row
255 for (var key in this.columns) {
256 var args = cb(key)
257 row.__cell(key, args[0], args[1])
258 }
259 return row
260}
\No newline at end of file