UNPKG

nbox-core

Version:

node-box-core js common utils box

812 lines (718 loc) 19.3 kB
/** * @file misc.js * @description 小函数集合 */ const SUB_COM_MISC = (function() { /** * @name 调试功能区 * @param {String} prompt * @param {String} msg */ function debugPrint(...args) { console.log(...args); } function debugPrintObj(obj) { console.log(JSON.stringify(obj)); } /** * @name 字符串、数值转换区 * @param {Number} n * @param {Number} padDigit */ function toString16(n, padDigit) { var s = '00000000' + n.toString(16).toUpperCase(); var r = s.slice(padDigit * (-1)); return r; } function pad0(n) { n = n.toString() return n[1] ? n : '0' + n } function atof2(str) { if (typeof str != "string") { return str; } var re = /([0-9]+.[0-9]{2})[0-9]*/; var fval = str.replace(re,"$1"); return parseFloat(fval); } function getRandom(N) { return 1 + Math.floor(Math.random() * N); } function getUnixTSmsec(dt) { dt = dt || (new Date()); var msec = dt.getTime(); return msec; } function getUnixTS(dt) { let sec = Math.round(getUnixTSmsec(dt) / 1000); return sec; } function UnixTS2DateTime(stamp) { let dt = new Date(); dt.setTime(stamp * 1000); return dt; } function UnixTS2DateTimeHRStr(stamp) { let dt = UnixTS2DateTime(stamp); return genDataTimeHRStr(dt); } function genDataTimeHRStr(date) { date = date || new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var hour = date.getHours(); var minute = date.getMinutes(); var second = date.getSeconds(); return [year, month, day].map(pad0).join('-') + ' ' + [hour, minute, second].map(pad0).join(':'); } function genDateTimeStr(sep, prefix, suffix) { sep = sep || ""; prefix = prefix || ""; suffix = suffix || ""; var date = new Date(); var year = toString16(date.getFullYear(), 4); var month = toString16(date.getMonth() + 1, 2); var day = toString16(date.getDate(), 2); var hour = toString16(date.getHours(), 2); var minute = toString16(date.getMinutes(), 2); var second = toString16(date.getSeconds(), 2); var msec = toString16(date.getMilliseconds(), 2); var mid = [year, month + day, hour + minute, second + msec].map(pad0).join(sep); var out = prefix + mid + suffix; return out; } /** * @name 计算与当前时间差 * @param {UnixTS} timestamp */ function getTimeDiff(timestamp) { let currentTime = (new Date()).getTime(); let dur = currentTime - timestamp * 1000; if (dur < 0) return null; let hour = Math.floor(dur / (1000 * 60 * 60)); let min = Math.floor(dur / (1000 * 60) % 60); let sec = Math.floor(dur / 1000 % 60); let day = Math.floor(hour / 24); let week = Math.floor(day / 7); let month = Math.floor(day / 30); let year = Math.floor(day / 365); const info = { y: year, m: month, w: week, d: day, H: hour, M: min, S: sec}; const nArr = [year, month, week, day, hour, min, sec]; const cnArr = ['年', '月', '周', '天', '小时', '分钟', '秒'].map(item => item + '前'); const enArr = ['year(s)', 'month(s)', 'week(s)', 'day(s)', 'hour(s)', 'minute(s)', 'second(s)'].map((item) => item + " ago" ); // 找到第一个不为0的即可. let diff = {info: info, cn: '刚刚', en: 'just'}; for (let i = 0; i < nArr.length; ++i) { if (nArr[i] > 0) { diff.cn = nArr[i] + cnArr[i]; diff.en = nArr[i] + ' ' + enArr[i]; break; } } return diff; } function getTimeDiffCN(timestamp) { const diff = getTimeDiff(timestamp); const newDiff = { info: diff.info, desc: diff.cn }; return newDiff; } function getTimeDiffEN(timestamp) { const diff = getTimeDiff(timestamp); const newDiff = { info: diff.info, desc: diff.en }; return newDiff; } /** * @name 获得文件扩展名 * @param {String} pathname 路径 */ function pathName2ExtName(pathname) { var extension = /\.([^.]*)$/.exec(pathname); if (extension) { extension = extension[1].toLowerCase(); } return extension; } /** * @name isEmpty * @param obj: * @description empty系列 * can be Array, Object, String, null, undefined. */ function isEmpty(obj) { let b = (obj === null || obj === undefined); if (!b) { switch (typeof obj) { case 'string': b = (obj.length == 0); break; case 'object': if (Array.isArray(obj)) b = (obj.length === 0); else b = (Object.keys(obj).length === 0); break; } } return b; } /** * @name isEqual * @description 判断对象相等 * @param {Object} objA * @param {Object} objB */ function isEqual(objA, objB) { const objAStr = JSON.stringify(objA); const objBStr = JSON.stringify(objB); const b = (objAStr.length === objBStr.length && objAStr === objBStr); return b; } /** * @name 周期性任务 * @param cb * @param interval * @constructor */ function CycleTask() { this.start = function(cb, interval) { this.timer = null; this.interval = interval || 1000; this.timer = setInterval(cb, this.interval); }; this.stop = function() { if (this.timer) { clearInterval(this.timer); this.timer = null; } }; } /** * 对外接口 * @type {Object} */ const out = { // debug调试 debugPrint, debugPrintObj, // 数字、串处理 toString16, pad0, atof2, getRandom, // 时间日期 getUnixTSmsec, getUnixTS, getTimeDiff, getTimeDiffCN, getTimeDiffEN, UnixTS2DateTime, UnixTS2DateTimeHRStr, genDataTimeHRStr, genDateTimeStr, // 文件路径 pathName2ExtName, // 对象 isEmpty, isEqual, // 任务相关 CycleTask, // Bound. EndGuard: 'EndGuard' }; return out; })(); // console.log('misc: ', SUB_COM_MISC); /** * @file strfmt * @description 字符串格式化 */ const SUB_COM_STRFMT = (function() { // import { sprintf, vsprintf } from 'sprintf-js'; const spf = require('sprintf-js'); const { sprintf, vsprintf } = spf; const { genDataTimeHRStr } = SUB_COM_MISC; /** * @name tsprintf * @description time-sprintf * @param {Object} obj {level: info, errno, subject, prompt} */ function tsprintf(obj) { let stime = genDataTimeHRStr(); let combFmt = '%s'; let combArgs = [stime]; if (obj.level) { combFmt += ' | %s'; combArgs.push(obj.level.toUpperCase()); } if (obj.subject) { combFmt += ' | %s'; combArgs.push(obj.subject); } if (obj.errno !== undefined) { combFmt += (obj.errno === 0) ? ' | SUCC' : ` | FAIL=${obj.errno}`; } if (obj.prompt) { combFmt += ' | ' + obj.prompt; combArgs = combArgs.concat(obj.args); } let s = vsprintf(combFmt, combArgs); return s; } function tsprintf2(prompt, ...args) { return tsprintf({prompt, args}); } function tsprintf3(level, prompt, ...args) { return tsprintf({level, prompt, args}); } function tsprintf4(subject, level, prompt, ...args) { return tsprintf({subject, level, prompt, args}); } function tsprintf5(errno, subject, level, prompt, ...args) { return tsprintf({errno, subject, level, prompt, args}); } /** * @name jtsprintf * @description json-time-sprintf * @param {Object} obj {level: info, errno, subject, prompt} */ function jtsprintf(obj) { let stime = genDataTimeHRStr(); let res = {stime: stime}; if (obj.level) { res.level = obj.level.toUpperCase(); } if (obj.subject) { res.subject = obj.subject; } if (obj.errno !== undefined) { res.errno = obj.errno; if (obj.errmsg !== undefined) { res.errmsg = obj.errmsg; } else { res.errmsg = (obj.errno === 0) ? 'SUCC' : `FAIL=${obj.errno}`; } } if (obj.prompt) { res.content = vsprintf(obj.prompt, obj.args); } return res; } function jtsprintf2(prompt, ...args) { return jtsprintf({prompt, args}); } function jtsprintf3(level, prompt, ...args) { return jtsprintf({level, prompt, args}); } function jtsprintf4(subject, level, prompt, ...args) { return jtsprintf({subject, level, prompt, args}); } function jtsprintf5(errno, subject, level, prompt, ...args) { return jtsprintf({errno, subject, level, prompt, args}); } /** * @description 对外接口 */ const out = { sprintf, // 带时间日期plain字符串版本 tsprintf, tsprintf2, tsprintf3, tsprintf4, tsprintf5, // 带时间日期json对象版本. jtsprintf, jtsprintf2, jtsprintf3, jtsprintf4, jtsprintf5 }; return out; })(); /** * @name logger * @description 基本Logger */ const SUB_COM_LOGGER = (function() { const strfmt = SUB_COM_STRFMT; const { debugPrint, CycleTask } = SUB_COM_MISC; const LogLevelNameTable = [ { id: 0, name: 'none', alias: 'NUL' }, { id: 1, name: 'crit', alias: 'CRT' }, { id: 2, name: 'error', alias: 'ERR' }, { id: 4, name: 'warning', alias: 'WRN' }, { id: 8, name: 'info', alias: 'INF' }, { id: 16, name: 'verbose', alias: 'VRB' }, { id: 32, name: 'debug', alias: 'DBG' }, { id: 64, name: 'perf', alias: 'PRF' }, { id: 128, name: 'trace', alias: 'TRC' } ]; /** * @name 日志等级辅助类 */ class LogLevelHelper { constructor(maxCombLevel) { this.maxCombLevel = maxCombLevel; // 仅输出这个等级以下的日志. } canOutput(id) { return id <= this.maxCombLevel; } setOutputLevel(combLevel) { this.maxCombLevel = combLevel; } getStdNameById(id) { const index = this.getIndex(id); const res = LogLevelNameTable[index]; return res; } getStdNameByName(name) { return this.verify(name).alias; } getId(name) { return this.verify(name).id; } /** * @description 内部方法 */ getIndex(id) { let index = 0; for (; 2 << index <= id; ++index) {} return (2 << index === id && index < LogLevelNameTable.length) ? index : 0; } verify(nameOrId) { let res = { index: LogLevelNameTable[0].id, canOutput: false, name: '' }; if (typeof nameOrId === 'number') { const id = nameOrId; const index = this.getIndex(id); const item = LogLevelNameTable[index]; res = { index, item, canOutput: this.canOutput(item.id), name: item.alias }; } else if (typeof nameOrId === 'string') { const name = nameOrId; const upName = name.toUpperCase(); const lowName = name.toLowerCase(); for (let i = 0; i < LogLevelNameTable.length; ++i) { const item = LogLevelNameTable[i]; if (lowName === item.name || upName === item.alias) { res = { index: i, item: item, canOutput: this.canOutput(item.id), name: item.alias }; break; } } } return res; } }; /** * @class LoggerBase * @description 日志基类 */ class LoggerBase { constructor() { this.option = { fmt: 'json', level: 255 }; this.history = []; // 环形Buffer todo this.levelHelper = new LogLevelHelper(this.option.level); } write2(prompt, ...args) { return this.write({prompt, args}); } write3(level, prompt, ...args) { return this.write({level, prompt, args}); } write4(subject, level, prompt, ...args) { return this.write4({subject, level, prompt, args}); } write5(errno, subject, level, prompt, ...args) { return this.write({errno, subject, level, prompt, args}); } write(combObj) { // 对Level进行格式化规整. combObj.canOutput = true; if (combObj.level !== undefined) { const res = this.levelHelper.verify(combObj.level); combObj.canOutput = res.canOutput; combObj.level = res.name; } const fn = (this.option.fmt === 'json') ? strfmt.jtsprintf : strfmt.tsprintf; const item = fn(combObj); this.writeOneItem(item); // this.history.push(item); } // 写日志-子类可重写此方法-模板方法模式. writeOneItem(item) { } } /** * @name SyncLogger * @description 同步写入日志类 */ class SyncLogger extends LoggerBase { constructor() { super(); this.file = null; } writeOneItem(item) { console.log(item); } } /** * @class AsyncLogger * @description 异步写入日志类 */ class AsyncLogger extends LoggerBase { constructor() { super(); this.task = null; this.items = []; } open(option = {}, freezed = true) { // 更新选项 option.interval = option.interval || 500; this.option = Object.assign({}, super.option, this.option, option); // 子类自己open let that = this; this.task = new CycleTask(); this.task.start( function() { let item = null; while ((item = that.items.pop()) != null) { that.doWriteOneItem(item); } }, this.option.interval); } close() { this.task.stop(); } writeOneItem(item) { this.items.push(item); } handle() { } // 派生类,可以继续模版方法模式. doWriteOneItem(item) { debugPrint(item); } } let logger = new AsyncLogger(); /** * @description 外部接口. */ const out = { SyncLogger, AsyncLogger, logger }; return out; })(); /** * @file validator.js * @description 数字、字符串校验相关 */ const SUB_COM_VALIDATOR = (function() { class Validator { /** * 验证必填元素 */ static required(value) { if (typeof value === 'number') { value = value.toString() } else if (typeof value === 'boolean') { return !0 } return value && value.length > 0 } /** * 重复验证 */ static noDuplicate(values) { for (let i = 0; i < values.length; i++) { for (let j = 0; j < values.length; j++) { if (values[i] == values[j] && i != j) { return false; } } } return true; } /** * 验证电子邮箱格式 */ static email(value) { return this.optional(value) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value) } /** * 验证手机格式 */ static tel(value) { return this.optional(value) || /^1[34578]\d{9}$/.test(value) } /** * 验证URL格式 */ static url(value) { return this.optional(value) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value) } /** * 验证日期格式 */ static date(value) { return this.optional(value) || !/Invalid|NaN/.test(new Date(value).toString()) } /** * 验证ISO类型的日期格式 */ static dateISO(value) { return this.optional(value) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value) } /** * 验证十进制数字 */ static number(value) { return this.optional(value) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value) } /** * 验证整数 */ static digits(value) { return this.optional(value) || /^\d+$/.test(value) } /** * 验证身份证号码 */ static idcard(value) { return this.optional(value) || /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value) } /** * 验证两个输入框的内容是否相同 */ static equalTo(value, param) { return this.optional(value) || value === that.scope.detail.value[param] } /** * 验证是否包含某个值 */ static contains(value, param) { return this.optional(value) || value.indexOf(param) >= 0 } /** * 验证最小长度 */ static minlength(value, param) { return this.optional(value) || value.length >= param } /** * 验证最大长度 */ static maxlength(value, param) { return this.optional(value) || value.length <= param } /** * 验证一个长度范围[min, max] */ static rangelength(value, param) { return this.optional(value) || (value.length >= param[0] && value.length <= param[1]) } /** * 验证最小值 */ static min(value, param) { return this.optional(value) || Number(value) >= Number(param); } /** * 验证最大值 */ static max(value, param) { return this.optional(value) || Number(value) <= Number(param); } /** * 验证时间 */ static after(value, param) { return this.optional(value) || value >= param; } /** * 验证时间 */ static before(value, param) { return this.optional(value) || value <= param; } /** * 验证一个值范围[min, max] */ static range(value, param) { return this.optional(value) || (value >= param[0] && value <= param[1]) } /** * 判断输入值是否为空 */ static optional(value) { return !this.required(value) && 'dependency-mismatch' } /** * 判断升级条件 */ static upgradeFee(value, param) { return (param - value) > 0 || param == null; } } const out = { Validator }; return out; })(); /** * @file bar.js * @description 接口导出规范样品文件 - bar */ const SUB_FOOBAR_BAR = (function() { function add(x, y) { return x + y; } function mult(x, y) { return x * y; } const out = { add, mult }; return out; })(); /** * @file foo.js * @description 接口导出规范样品文件 - foo */ const SUB_FOOBAR_FOO = (function() { function add(x, y) { return x + y; } function mult(x, y) { return x * y; } const foo = { addF: add, multF: mult }; return foo; })(); /** * @file index.js * @description nbox-core 统一对外接口文件 */ /** * @name SUB_COM_OVERRIDE * @description 私有override接口 */ const SUB_COM_OVERRIDE = { debugLog: function(...args) { console.log(...args); }, traceLog: function(...args) { console.log(...args); } }; const CORE = Object.assign( {}, SUB_COM_MISC, SUB_COM_STRFMT, SUB_COM_LOGGER, SUB_COM_VALIDATOR, SUB_COM_OVERRIDE, SUB_FOOBAR_FOO, SUB_FOOBAR_BAR ); CORE.help = () => { console.log('core: ', module.exports); }; module.exports = CORE;