UNPKG

2.95 kBJavaScriptView Raw
1import { round } from '@aryth/math'
2import { STR } from '@typen/enum-data-types'
3import { base3ToScale, trailZero } from '../util/humanScale.js'
4
5const DEFAULT_SENTENCE = 'progress [{bar}] {progress}% | ETA: {eta}s | {value}/{total}'
6
7export class Layout {
8 /**
9 * @param {object} [options]
10 * @param {number} [options.size] size of the progressbar in chars
11 * @param {string[]|string} [options.char]
12 * @param {string} [options.glue]
13 * @param {string} [options.sentence]
14 * @param {boolean} [options.autoZero = false] autoZero - false
15 * @param {function(State):string} [options.bar]
16 * @param {function(State):string} [options.degree]
17 * @param {function(State,object):string} [options.format]
18 */
19 constructor(options) {
20 const char = typeof options.char === STR ? [ options.char, ' ' ] : Array.isArray(options.char) ? options.char : [ '=', '-' ]
21 const [ x, y ] = char
22 this.size = options.size ?? 24
23 this.chars = [ x.repeat(this.size + 1), y.repeat(this.size + 1) ]
24 this.glue = options.glue ?? ''
25 this.autoZero = options.autoZero ?? false // autoZero - false
26 this.sentence = options.sentence ?? DEFAULT_SENTENCE
27 if (options.bar) this.bar = options.bar.bind(this)
28 if (options.degree) this.degree = options.degree.bind(this)
29 if (options.format) this.format = options.format.bind(this)
30 }
31
32 static build(options) {
33 return new Layout(options)
34 }
35
36 bar(state) {
37 const { progress } = state
38 const { chars, glue, size } = this
39 const
40 lenX = round(progress * size),
41 lenY = size - lenX
42 const [ x, y ] = chars
43 // generate bar string by stripping the pre-rendered strings
44 return x.slice(0, lenX) + glue + y.slice(0, lenY)
45 }
46
47 get fullBar() { return this.chars[0].slice(0, this.size) }
48 get zeroBar() { return this.chars[1].slice(0, this.size) }
49
50 degree(state) {
51 let { value, total } = state
52 const { base3 = true, decimal = false } = this
53 if (!base3) return `${round(value)}/${total}`
54 const thousand = decimal ? 1000 : 1024
55 let base3Level = 0
56 while (total > thousand) { // base3Level <= base3
57 total /= thousand
58 value /= thousand
59 base3Level++
60 }
61 const t = trailZero(total)
62 const v = trailZero(value).padStart(t.length)
63 // return { value: valueText, total: totalText, scale: base3ToScale(base3, dec) }
64 return `${v}/${t} ${base3ToScale(base3Level, decimal)}`
65 }
66 /**
67 *
68 * @param {State|object} state
69 * @returns {string}
70 */
71 format(state) {
72 return this.sentence?.replace(/\{(\w+)\}/g, (match, key) => {
73 if (key === 'bar') return this.bar(state)
74 if (key === 'degree') return this.degree(state)
75 if (key in state) return state[key]
76 return match
77 })
78 }
79}
\No newline at end of file