All files / libs/sys xlog.js

100% Statements 41/41
100% Branches 25/25
100% Functions 9/9
100% Lines 39/39
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                1x 1x 1x 1x                                                     1x 1x                                               1x 30x   30x   30x 30x 30x   30x 30x 30x 30x   30x   26x 26x   20x 49x 25x 25x   24x 24x   49x   20x                 1x           2x             30x             4x             4x 4x 4x           1x 3x     4x 3x         2x      
/**
 * @module      libs/sys/xlog
 * @createdAt   2016-07-15
 *
 * @copyright   Copyright (c) 2016 Zhonglei Qiu
 * @license     Licensed under the MIT license.
 */
 
var util = require('util')
var extend = require('./extendFormat')
var clog = require('./clog')
var cliTextSize = require('../tty/cliTextSize')
 
/**
 * 输出带样式的字符串,拥有 {@link module:libs/sys/clog} 的所有功能
 *
 * FORMAT  |  EXPLAIN
 * --------|-----------
 * %d      |  格式化成整数,使用了 parseInt
 * %\d*f   |  格式化成浮点数,使用了 parseFloat,中间的数字表示保存的小数位数
 * %j, %o  |  格式化成对象,使用了原生的 util.format('%j', val)
 * %c      |  格式化成颜色,使用了 {@link module:libs/sys/clog.format}
 * %...s   |  格式化字符串,支持对齐,参数复杂,用 ... 表示省略,说情参看 {@link module:libs/sys/xlog.align}
 *
 * @param {String} template   模板
 * @param {...*}   [arg]      模板的参数
 * @param {String} [template] 第二个模板,后面可以继续接 ...arg, template, ...arg, ...
 *
 * @example
 * xlog('price %2f$', 100)  => 'price 100.00$'
 *
 * xlog('%5:<.>s', 'a')     => '<<a>>'
 * xlog('%5:<.>s', 'abc')   => '<abc>'
 *
 * @method
 * @author Zhonglei Qiu
 * @since  2.0.0
 */
module.exports = xlog
exports = module.exports
 
/**
 * 对齐 str 字符串
 *
 * @type   {Function}
 * @param  {String} str    要对齐的字符串
 * @param  {String} format 对齐规则,规则如下
 *
 *  EXAMPLE    |    EXPLAIN
 *  -----------|----------------
 *  3          |  至少有3个字符,没有的话在左边补【默认字符】
 *  .3         |  至少有3个字符,没有的话在右边补【默认字符】
 *  1.2        |  至少3个字符,不足的话左右两边填充【默认字符】,先填左,再填右,再填右
 *  1.2:_      |  至少3个字符,没有的话在左边补 _,在右边补【默认字符】
 *  1.2:.0     |  至少3个字符,没有的话在左边补【默认字符】,在右边补 0
 *  1.2:_.0    |  至少3个字符,没有的话在左边补 _,在右边补 0
 *
 * @param  {Object} opts   配置选项
 * @param  {String} [opts.leftPad=" "]    左侧填充的【默认字符】
 * @param  {String} [opts.rightPad=" "]   右侧填充的【默认字符】
 *
 * @return {String}        对齐后的 str
 */
exports.align = function(str, format, opts) {
  opts = opts || {}
  var lLen, rLen, lPad, rPad, i, diff
  var flag = true
 
  var parts = format.split(':')
  var lens = parts.shift().split('.')
  var pads = parts.join(':').split('.')
 
  lLen = parseInt(lens[0] || '0', 10)
  rLen = parseInt(lens[1] || '0', 10)
  lPad = pads[0] || opts.leftPad || ' '
  rPad = pads[1] || opts.rightPad || ' '
 
  if (lLen === 0 && rLen === 0) return str
 
  diff = lLen + rLen - cliTextSize(str)
  if (diff <= 0) return str
 
  for (i = 0; i < diff; i++) {
    if ((flag || rLen === 0) && lLen > 0) {
      str = lPad + str
      lLen--
    } else {
      str += rPad
      rLen--
    }
    flag = !flag
  }
  return str
}
 
/**
 * {@link module:libs/sys/xlog} 使用的 format 函数,类似于 console.log 使用了 util.format 函数
 *
 * @method
 * @return {String}  格式化后的字符串
 */
exports.format = extend([
  clog.colorMatcher,
  {
    match: /%[jo]/,
    order: 1,
    handle: function(val) {
      return util.format('%j', val)
    }
  },
  {
    match: /%(?:\d+)?\.?(?:\d+)?(?::.\.?.?)?s/,
    order: 1,
    handle: function(val, format) {
      return exports.align(String(val), format.slice(1, -1))
    }
  },
  {
    match: /%d/,
    order: 2,
    handle: function(val) {
      return parseInt(val, 10)
    }
  },
  {
    match: /%\d*f/,
    order: 2,
    handle: function(val, format) {
      var fixed = parseInt(format.substr(1), 10)
      val = parseFloat(val)
      return fixed ? val.toFixed(fixed) : val.toString()
    }
  }
]);
 
// @FIXME 这些字段无法生成 jsdoc
['autoResetAtEnd', 'autoResetAtGroupEnd', 'NAMED_COLORS'].forEach(function(k) {
  Object.defineProperty(xlog, k, {
    enumerable: true,
    configurable: true,
    set: function(val) { clog[k] = val },
    get: function() { return clog[k] }
  })
})
 
function xlog() {
  console.log(exports.format.apply(null, arguments))
}