gcl
Version:
码农村nodejs类库,完成解决回调陷阱,配置框架,IOC框架,统一多DB访问框架,可扩展日志框架和io/db/net/thread/pool 克隆表达式,加解密算法等等一系列基础类库和算法的实现
1,692 lines (1,656 loc) • 47.5 kB
JavaScript
;
import util from "util";
import { parse, resolve, normalize } from "path";
import {
createHash,
createHmac,
createSign,
createVerify,
createCipheriv,
createCipher,
createDecipheriv,
createDecipher,
} from "crypto";
import v4 from "uuid/v4";
import SnowflakeId from "snowflake-id";
import Decimal from "decimal.js";
import parser from "fast-xml-parser";
import he from "he";
import pako from "pako";
/*
减少语句路径
少用pop,push 改为i++--操作和[length]=new
频繁new的对象改为inherit2方法 尽管inherit2方法无法私有对象
多用三元?少用if
多用空方法 少用if
除非必须 少用delete
使用 || 代替 getValue 或者3元
使用for if(i++>1) 判断是否为空
使用substr lastIndexOf 代替split
尽量使用原生方法(native)代替自己的方法
*/
export const environment = {
os: process.cwd().indexOf("\\") >= 0 ? "windows" : "linux/unix",
splitChar: process.cwd().indexOf("\\") >= 0 ? "\\" : "/",
};
/**
* 采用代理模式给类和类内方法添加属性
* @param(调用时的原方法对象,键值,键值上的一个新值)
* @returns decorator
*/
export const prop = (target, k, v) => {
target[k] = target[k] || [];
target[k].push(v);
};
/**
* 添加link属性用于连接方法需求
* @param (link)
*/
export const link = (url) => {
return (target) => prop(target, "link", url);
};
/**
* 添加多个desc属性用于动态显示方法描述
* @param (desc)
*/
export const desc = (des) => {
return (target) => prop(target, "desc", des);
};
/**
* 判断对象是否有效 含有 not in (null,undefined,'null','',\s+,0,false)
*/
export const isValid = (data) =>
!!data && (data.replace == undefined || data.replace(/\s/g, "").length > 0);
/**
* 三元表达式,简化 多数情况可以用默认值或者 value || defaultValue 替换,但是当其为null时则不好判断
*/
export const getValue = (data, defaultData) =>
isValid(data) ? data : defaultData;
/**
* 私有方法,返回_,__命名的一个自身对象和一个私有对象。一般在类方法第一句使用
* @param(this,__)
* @return({this,private})
*/
export const pris = () => {
const key = Symbol("private");
return (obj, priv) => {
obj[key] = (priv ? merge(obj[key], priv) : obj[key]) || {};
return {
_: obj,
__: obj[key],
};
};
};
/**
* 字符串格式化,使用<%k.v%>,{k.v}等等方式进行递进的属性替换,当字符串模板不可用时使用。
*/
export const format = function (s, o) {
if (!s || !o) {
return getValue(s, "");
}
if (s.indexOf("<%=") >= 0)
return __.funrep(s, o, /<%=[^(%>)]+%>/gi, /<%=/g, /%>/g);
if (s.indexOf("{") >= 0)
return __.funrep(s, o, /\{[^(})]+\}/gi, /\{/g, /\}/g);
return s;
};
/**
* 返回私有StringBuilder对象实例,含有
*/
export const sb = () => new __.StringBuilder();
export const showException = (name = "", e) => {
if (isValid(e)) {
name +=
"\r\nmessage:" +
getValue(e.message, e) +
(e.stack
? "\r\nstack:" +
e.stack +
(e.fileName ? "\r\nfile:" + e.fileName : "") +
(e.lineNumber ? "\r\nlineNumber:" + e.lineNumber : "")
: e.description
? "\r\ndescription:" + e.description
: "");
console.log(name);
}
};
export const showEx = showException;
export const tryF = (func, errcall) => new Proxy(func, __.tryHandle(errcall));
export const tryC = (func, errcall) => tryF(func, errcall)();
export const tryC2 = (err, func, errcall) =>
err ? (errcall || __.showEx)(e) : tryC(func, errcall);
export const watch = (restart) => {
if (!__.start || restart) {
__.start = new Date();
console.log("VESH.watch开始" + __.start);
} else {
console.log("VESH.watch 持续了:" + __.start.diff("ms", new Date()));
}
};
export const isArray = Array.isArray;
export const once = (func, timeout) => {
timeout = timeout || 1;
if (func.timeoutID) {
clearTimeout(func.timeoutID);
}
if (timeout == 1) process.nextTick(() => tryC(func));
else func.timeoutID = setTimeout(() => tryC(func), timeout);
};
//exp的非链式操作与链式操作,非链式不保证执行顺序,链式保证执行顺序,对象的随机并发操作与顺序执行,数组的map随机并发操作与顺序执行
//使用once满足非promise截止的请求,循环全部是promise截止的r
//根据执行的源头不同分为 whileC(链式、非链式,promise),forC(链式、非链式,promise),each(链式、非链式,promise),next(链式 promise),finalC(非链式 promise) 不同种类 根据链式与非链式,
//保证异步的同步执行
//保证当直接返回true或者call(null,true)时中断循环
export const whileC = (exp, func, isSequ = false) =>
isSequ
? isSequ > 1
? __.disorderlWhile(exp, func, isSequ)
: __.sequfunc(exp, func, exp())
: __.disorderfunc(exp, func, exp());
export const each = (data, func, isSequ = false) =>
isSequ
? isSequ > 1
? __.disorderlEach(data, func, isSequ)
: __.sequEach(data, func)
: __.disorderEach(data, func);
export const forC = (obj, func, isSequ = false) =>
isSequ
? isSequ > 1
? __.disorderlFor(obj, func, isSequ)
: __.sequFor(obj, func)
: __.disorderFor(obj, func);
export const finalC = (...funs) => {
const data = {},
finalF = funs.pop();
return each(funs, (v) => callback2(v, null, data)).then(() =>
callback2(finalF, null, data),
);
};
export const next = (...funs) => {
const data = {};
return each(funs, (v) => callback2(v, null, data), true);
};
/**
* 用于链式处理事务 参数为成对定义的正向和回滚方法{go:func,rollback:func} 也可简写为 {g:func,r:func}
*/
export const tnext = (...funs) => {
let i = 1;
const data = {},
goerr = () => {
throw new Error("请在第" + i + "个对象定义g或者go方法");
},
rollbacks = [];
return each(
funs,
(v) =>
callback2(v.g || v.go || goerr, v, data)
.then((v2) => {
rollbacks.unshift(
v.r ||
v.rollback ||
(function () {
throw new Error("请在第" + i + "个对象定义r或者rollback方法");
})(),
);
i++;
return v2;
})
.catch((e2) => {
if (typeof e2 === "string" || typeof e2 === "boolean")
rollbacks.unshift(
v.r ||
v.rollback ||
(function () {
throw new Error("请在第" + i + "个对象定义r或者rollback方法");
})(),
);
throw typeof e2 === "string" ? new Error(e2) : e2;
}),
true,
).catch((e) =>
next(...rollbacks).then(() => {
throw e;
}),
);
};
/**
* 异步改同步请求
* 兼容直接返回值,返回一个Promise或者返回undefined 最后一个参数调用call(e,data) 三种情况
* @param {*} args
*/
export const callback2 = function (...args) {
return new Promise(async (re, rj) => {
try {
const call = (e, data) => (e ? rj(e) : re(data));
const func = args[0];
const _this = args[1] || null;
const paras = args.slice(2).concat([call]);
let data = Reflect.apply(func, _this, paras); //this 不对 Reflect.apply(func, null, paras);
if (data && data.then) data = (await data) || false;
switch (typeof data) {
case "function":
data(call);
case "undefined":
break;
default:
call(null, data);
break;
}
} catch (e) {
rj(e);
}
});
};
/**
* 仅适用最后一个参数为call的情况
* @param {*} args
*/
export const callback = function (...args) {
const func = args[0];
args[0] = function (...args2) {
const that = this;
Reflect.apply(func, that, args2);
};
return callback2(...args);
};
export const random = () => parseInt("" + __.index++ + new Date().getTime());
export const hashRandom = function (min = 0, max) {
return Math.floor(Math.abs(hash(guid()) % (max - min))) + min;
};
/**
* 获取字符串的哈希值
* @param {String} str
* @param {Boolean} caseSensitive
* @return {Number} hashCode
*/
export const hash = (str, caseSensitive = false) => {
str = str.toString();
if (!caseSensitive) {
str = str.toLowerCase();
}
// 1315423911=b'1001110011001111100011010100111'
let hash = 1315423911,
i,
ch;
for (i = str.length - 1; i >= 0; i--) {
ch = str.charCodeAt(i);
hash ^= (hash << 5) + ch + (hash >> 2);
}
return hash & 0x7fffffff;
};
/**
* 获取字符串的sha1 base64 哈希值
* @param {String} str
* @param {Boolean} caseSensitive
* @return {Number} hashCode
*/
export const hash2 = (str) => {
let ret = createHash("sha256").update(str).digest("base64");
return (
ret.substr(0, 2) +
ret.substr(11, 1) +
ret.substr(3, 10) +
ret.substr(2, 1) +
ret.substr(12)
);
};
export const formatPrice = function (
number,
decimals,
dec_point,
thousands_sep,
) {
number = (number + "").replace(/[^0-9+-Ee.]/g, "");
let n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 2 : Math.abs(decimals),
sep = typeof thousands_sep === "undefined" ? "," : thousands_sep,
dec = typeof dec_point === "undefined" ? "." : dec_point,
s = "",
toFixedFix = function (n, prec) {
const k = Math.pow(10, prec);
return "" + Math.round(n * k) / k;
};
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split(".");
if (s[0].length > 3) {
s[0] = s[0].replace(/B(?=(?:fd{3})+(?!d))/g, sep);
}
if ((s[1] || "").length < prec) {
s[1] = s[1] || "";
s[1] += new Array(prec - s[1].length + 1).join("0");
}
return s.join(dec);
};
/**
* 只更新标点符号不更新全半角文字的encode
* @param {String} html
* @return {String} encodeURIComponent之后的字段
*/
//replace(/[\r\n]+/g, '>v>j>').replace(/\s+/g, ' ').replace(/>v>j>/g, '\r\n').
export const encHtml = (html = "") =>
((html || "").match(__.encmatch) || [])
.join("")
.replace(__.encreg, (a) => __.encother[a] || encodeURIComponent(a));
export const decHtml = (html = "") => decodeURIComponent(html);
export const toJsonString = JSON.stringify;
export const json = JSON.parse;
/**
*
* @param {*} 二维数组
* @param {*} 是否需要引号
*/
export const toTJson = (data = [], quotation = true) => {
if (!isArray(data)) data = [data];
const res = [];
if (data[0] && isArray(data[0])) {
for (const i in data) {
res[i] = toTJson(data[i]);
}
} else {
//找到第一个不是数组的实例对象进行处理
res[0] = [];
for (const k in data[0]) {
res[0].push(quotation ? '"' + k + '"' : "" + k);
}
for (const v in data) {
const obj = [];
for (const k2 in data[0])
obj.push(__.getTJsonValue(data[v][k2], quotation));
res.push(obj);
}
}
return res;
};
export const getType = (x = null) => {
if (x == null) {
return "null";
}
const t = typeof x;
if (t != "object" && t != "Object") {
return t;
}
if (isArray(x)) {
return "Array";
}
let c = Object.prototype.toString.apply(x);
c = c.substring(8, c.length - 1);
if (c != "Object") {
return c;
}
if (x.constructor == Object) {
return c;
}
if (
x.prototype &&
"classname" in x.prototype.constructor &&
typeof x.prototype.constructor.classname == "string"
) {
return x.constructor.prototype.classname;
}
return "ukObject";
};
export const merge = (...argu) => {
if (argu.length < 2) {
return argu[0] ? argu[0] : {};
}
if (argu.length > 0 && true === argu[argu.length - 1]) {
let _ = argu[0];
for (let i2 = 1; i2 < argu.length; i2++) _ = __.merge(_, argu[i2]);
return _;
} else {
let _ = {};
for (let i2 = 0; i2 < argu.length; i2++) _ = __.merge(_, argu[i2]);
return _;
}
};
export const inherits = function (parent, args) {
//绕过了parent的构造函数,重新链接原型链条
const _temp = (function () {
const F = function () {};
util.inherits(F, parent);
//F.prototype = parent.prototype;
F.prototype.isF = true;
return new F();
})();
_temp.constructor = parent;
if (!this.prototype) {
//这里确认是实例
//确定是打断了原型链 使得this的原型为Object
parent.apply(this, args);
//从新接驳原型链 使得原型链上的prototype都设置到最早的类的prototype上了
if (this.__proto__ && !this.__proto__.isF) {
util.inherits(this.__proto__.constructor, _temp.__proto__.constructor);
//this.__proto__.constructor.prototype = _temp.__proto__.constructor.prototype;
}
//son.prototype = _temp; //这里可以分层 但是会使得prototype实例变了又变 废弃
this.__proto__ = _temp;
//父类方法只能找到静态方法
this.base = this.__proto__.constructor.prototype;
} else {
console.log("如果失败,需要配合子类构造函数中使用parent.apply(this,[***])");
//这里确认是类定义
this.prototype = _temp;
}
};
export const create2 = function (type, args) {
if (typeof type == "function") {
return new type(...args);
} else showException("请传入类定义");
};
export const create = function (type, args) {
if (typeof type == "function") {
args = isArray(args) ? args : [args];
let ret = "(new type(";
if (isArray(args)) {
for (const i in args) {
ret += "args[" + i + "],";
}
if (args.length > 0) {
ret = ret.substr(0, ret.length - 1);
}
}
return eval(ret + "))");
} else showException("请传入类定义");
};
/**
* 分别尝试全路径.js/全路径.njs/全路径加载类 并对处理结果进行缓存 会导致热更新失败错误!
* @param {text} md5源串
*/
export const md5 = function (text) {
return createHash("md5").update(text, "utf-8").digest("hex");
};
/**
* 扩展hash
* https://www.jb51.net/article/50668.htm
* @param {string} text 原文
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 utf8
* @param {string} ocode 出栈 譬如 hex
*/
export const xhash = function (
text,
type = "md5",
ecode = "utf8",
ocode = "hex",
) {
return createHash(type).update(text, ecode).digest(ocode);
};
/**
* 带秘钥hash
* https://www.jb51.net/article/50668.htm
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 utf8
* @param {string} ocode 出栈 譬如 hex
*/
export const xhmac = function (
text,
key,
type = "sha256",
ecode = "utf8",
ocode = "base64",
) {
return createHmac(type, key).update(text, ecode).digest(ocode);
};
/**
* 带秘钥生成签名
* https://www.jb51.net/article/50668.htm
* openssl list-public-key-algorithms 看所有的签名算法
* @param {*} text
* @param {*} key
* @param {*} type
* @param {*} keycode
*/
export const xsign = function (
text,
key,
type = "RSA-SHA256",
keycode = "hex",
) {
const sign = createSign(type);
sign.update(text);
return sign.sign(key, keycode);
};
/**
* 带秘钥验证签名
* https://www.jb51.net/article/50668.htm
* openssl list-public-key-algorithms 看所有的签名算法
* @param {*} text
* @param {*} key
* @param {*} type
* @param {*} keycode
*/
export const xverify = function (
text,
key,
type = "RSA-SHA256",
keycode = "hex",
) {
const sign = createVerify(type);
sign.update(text);
return sign.verify(key, keycode);
};
/**
* 加密
* https://www.jb51.net/article/50668.htm
* https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 utf8
* @param {string} ocode 出栈 譬如 base64
*/
export const xcrypt = function (
text,
key,
type = "aes-256-cbc",
ecode = "utf8",
ocode = "base64",
) {
var cipher = createCipher(type, key);
return cipher.update(text, ecode, ocode) + cipher.final(ocode);
};
/**
* 解密
* https://www.jb51.net/article/50668.htm
* https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 base64
* @param {string} ocode 出栈 譬如 utf8
*/
export const xdcrypt = function (
text,
key,
type = "aes-256-cbc",
ecode = "base64",
ocode = "utf8",
) {
var cipher = createDecipher(type, key);
return cipher.update(text, ecode, ocode) + cipher.final(ocode);
};
/**
* 加密
* https://www.jb51.net/article/50668.htm
* https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} iv 偏移 一般是 8或者16位默认可用Buffer.alloc(0)
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 utf8
* @param {string} ocode 出栈 譬如 base64
*/
export const xcryptiv = function (
text,
key,
iv = Buffer.alloc(0),
type = "aes-256-cbc",
ecode = "utf8",
ocode = "base64",
) {
var cipher = createCipheriv(type, key, iv);
return cipher.update(text, ecode, ocode) + cipher.final(ocode);
};
/**
* 解密
* https://www.jb51.net/article/50668.htm
* https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} iv 偏移 一般是 8或者16位默认可用Buffer.alloc(0)
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 base64
* @param {string} ocode 出栈 譬如 utf8
*/
export const xdcryptiv = function (
text,
key,
iv = Buffer.alloc(0),
type = "aes-256-cbc",
ecode = "base64",
ocode = "utf8",
) {
var cipher = createCipheriv(type, key, iv);
return cipher.update(text, ecode, ocode) + cipher.final(ocode);
};
/**
* 加密 已经被 xcryptiv取代
* https://www.jb51.net/article/50668.htm
* https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} ecode 入栈 譬如 utf8
* @param {string} ocode 出栈 譬如 base64
*/
export const xcrypt_a1e = function (
text,
key,
iv = "",
ecode = "utf8",
ocode = "base64",
) {
var cipher = createCipheriv("aes-128-ecb", key, iv);
cipher.setAutoPadding(true);
return cipher.update(text, ecode, ocode) + cipher.final(ocode);
};
/**
* 解密 已经被 xdcryptiv取代
* https://www.jb51.net/article/50668.htm
* https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0
* @param {string} text 原文
* @param {string} key 秘钥 譬如 111
* @param {string} type 算法 譬如 md5
* @param {string} ecode 入栈 譬如 base64
* @param {string} ocode 出栈 譬如 utf8
*/
export const xdcrypt_a1e = function (
text,
key,
iv = "",
ecode = "base64",
ocode = "utf8",
) {
var cipher = createDecipheriv("aes-128-ecb", key, iv);
cipher.setAutoPadding(true);
return cipher.update(text, ecode, ocode) + cipher.final(ocode);
};
/**
专门给Java 的 AES方法提供密码转换,
https://www.zhihuclub.com/149867.shtml
一般可以用 xdcrypt_a1e(string,SHA1PRNG(key)); 与Java互通
*/
export const SHA1PRNG = function (pwd) {
return Buffer.from(
createHash("sha1")
.update(createHash("sha1").update(pwd).digest("buffer"))
.digest("hex")
.substring(0, 32),
"hex",
);
};
/**
* 分别尝试全路径.js/全路径.njs/全路径加载类 并对处理结果进行缓存 会导致热更新失败错误!
* @param {文件上级路径} path
* @param {类名} base
*/
export const include = function (path, base = null) {
const paths = `${path}|${base}`;
return (
__.include[paths] ||
(function () {
if (__.unclude[paths]) throw new Error(`加载${paths}失败!`);
__.include[paths] = (function () {
try {
if (path.startWith("\\") || path.startWith("/")) {
base = base
? format(base)
: parse(resolve(normalize(process.mainModule.filename))).dir;
if ("windows".eq(environment.os || "")) {
//windows
base = base.replace(/\//g, "\\");
path = path.trim("/").trim("\\").replace(/\//g, "\\");
} else {
//linux
base = base.replace(/\\\\/g, "/");
path = path.trim("\\").trim("/").replace(/\\\\/g, "/");
}
try {
try {
return require(`${base}${environment.splitChar}${path}.njs`);
} catch (e2) {
if (
path.endWith("action") &&
e2.message.indexOf("action.njs") < 0
)
console.log(
`${base}${environment.splitChar}${path}.njs 加载失败!`,
e2.stack,
);
return require(`${base}${environment.splitChar}${path}.js`);
}
} catch (e3) {
return require(path);
}
} else return require(path);
} catch (e) {
//console.log(e.stack);
__.unclude[paths] = true;
throw new Error(`加载${paths}失败!!${e.stack}`);
}
})();
return __.include[paths];
})()
);
};
export const applyCAE = function (S) {
//功能出现严重问题 无法在ES6下使用
S[__.settings] = {};
S[__.exsettings] = {};
//获取不存在就配置
S.getSettings = function (key, data) {
if (!isValid(S[__.settings][key])) {
if (isValid(S[__.exsettings][key])) {
S[__.settings][key] = merge(getValue(data, {}), S[__.exsettings][key]);
delete S[__.exsettings][key];
} else S[__.settings][key] = getValue(data, {});
}
return S[__.settings][key];
};
//扩展默认配置
S.extendSettings = function (key, data) {
if (isValid(S[__.settings][key])) {
S[__.settings][key] = merge(S[__.settings][key], data);
} else {
if (S.exSettings[key]) {
S[__.exsettings][key] = merge(
S[__.exsettings][key],
getValue(data, {}),
);
} else {
S[__.exsettings][key] = getValue(data, {});
}
}
};
S.clearSettings = function () {
S[__.settings] = {};
};
S.registCommand = function (name, func) {
const comms = S.getSettings("comms", []);
const data = comms[name];
if (isValid(data) && typeof data != "function") {
func.apply(null, data);
}
comms[name] = func;
};
/*
V用于调用被调用页面注册的命令以处理异步命令调用,当命令尚未注册而已经被调用时,参数会先被缓存下来,然后当命令注册时,已知的参数再被调用。
--案例
S.callCommand('showXXList',[{id:1}])
*/
S.callCommand = function (name, data) {
const caller = null;
const comms = S.getSettings("comms", []);
const func = comms[name];
data = isArray(data) ? data : [data];
if (isValid(func) && typeof func == "function") {
once(function () {
func.apply(caller, data);
});
} else {
comms[name] = data;
}
};
/*
用来判断是否调用页面,当已经调用过(part),返回true,否则返回false;
--案例
if (!S.hasCommand('editor.open')) S.part("/FileServer/layout/editor/editor.htm");
*/
S.hasCommand = function (name) {
const comms = S.getSettings("comms", []);
const func = comms[name];
return isValid(func) && typeof func == "function";
};
/*
仅限iframe方式调用时,先取消原页面添加的方法
//业务逻辑深度交叉,iframe落后的控件连接方式时使用
一定要在part前
--案例
S.cleanCommand('editor.open');
S.part("/FileServer/layout/editor/editor.htm",null,"iframe",function(){});
*/
S.cleanCommand = function (name) {
const comms = S.getSettings("comms", []);
delete comms[name];
};
/*
V用于被调用页面注册命令以处理异步命令调用,当命令尚未注册而已经被调用时,参数会先被缓存下来,然后当命令注册时,已知的参数再被调用。
并约定1分钟内 允许注册者多次被触发
--案例
S.registEvent('showXXList',getData),S.registEvent(['showXXList',''],getData)
*/
S.registEvent = function (name, func, isTop) {
const fun = function (name, func, isTop) {
const events = S.getSettings("events", []);
let funs = events[name];
if (!isValid(funs)) {
funs = [];
events[name] = funs;
}
if (typeof func == "function") {
if (isTop && !funs.top) {
funs.top = func;
funs.unshift(func);
} else {
if (isTop && funs.top) {
showException("S.registEvent:" + name + " 事件已经有订阅者被置顶!");
}
funs.push(func);
}
let ecall = S.getSettings("eventcall", {});
ecall = ecall[name] ? ecall[name] : {};
if (ecall.time && ecall.time >= new Date().getTime()) {
once(function () {
func.apply(ecall.caller, ecall.data);
});
}
}
};
if (isArray(name)) {
each(
name,
function (v) {
fun(v, func, isTop);
return false;
},
true,
);
} else {
fun(name, func, isTop);
}
};
/*
V用于调用被调用页面注册的事件以处理异步命令调用,当命令尚未注册而已经被调用时,参数会先被缓存下来,然后当命令注册时,已知的参数再被调用。
并约定1分钟内 允许注册者多次被触发
--案例
S.callEvent('showXXList',[{id:1}])
*/
S.callEvent = function (name, data) {
const caller = null;
const events = S.getSettings("events", []);
const funs = events[name];
data = isArray(data) ? data : [data];
if (isValid(funs) && isArray(funs)) {
each(funs, function (func) {
//报错不下火线
tryC(function () {
func.apply(caller, data);
});
});
}
let ecall = S.getSettings("eventcall", {});
if (!ecall[name]) {
ecall[name] = {};
}
ecall = ecall[name];
ecall.time = new Date().add("n", 1).getTime();
ecall.data = data;
ecall.caller = caller;
};
/*
用来判断是否调用页面,当已经调用过(part),返回true,否则返回false;
--案例
if (!S.hasEvent('editor.open')) S.part("/FileServer/layout/editor/editor.htm");
*/
S.hasEvent = function (name) {
const events = S.getSettings("events", []);
const funs = events[name];
if (isValid(funs) && isArray(funs)) {
return true;
}
return false;
};
/*
仅限iframe方式调用时,先取消原页面添加的方法
//业务逻辑深度交叉,iframe落后的控件连接方式时使用
一定要在part前
--案例
S.cleanEvent('editor.open');
S.part("/FileServer/layout/editor/editor.htm",null,"iframe",function(){});
*/
S.cleanEvent = function (name) {
const events = S.getSettings("events", []);
delete events[name];
};
};
/**
* 转换文本内容为压缩格式
* @param {*} str
*/
export const deflateBase64 = function (str) {
return Buffer.from(pako.deflate(str, { to: "string" })).toString("base64");
};
/**
* base64还原文本内容
* @param {*} str
*/
export const inflateBase64 = function (str) {
var ret;
try {
ret = Buffer.from(str, "base64");
return pako.inflate(ret, { to: "string" });
} catch (e) {
ret = _decodeEmoji(str);
}
return ret || str;
};
export const encodeEmoji = deflateBase64;
export const decodeEmoji = inflateBase64;
/**
* 转换Emoji为base64格式
* @param {*} str
*/
export const _encodeEmoji = function (str) {
return __.convert2Base64(
encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode("0x" + p1);
}),
);
};
/**
* base64还原emoji
* @param {*} str
*/
export const _decodeEmoji = function (str) {
var ret;
try {
ret = __.convert2Binary(str).split("");
var ret2 = [];
ret.forEach(function (c) {
ret2.push("%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2));
});
return decodeURIComponent(ret2.join(""));
} catch (e) {
ret = decodeURIComponent(str);
}
return ret || str;
};
/**
* 生成xml解析对象 toJson用于转换xml2Json toXml用于转换json2xml
* @param {config} config
* 譬如 attributeNamePrefix: "@_",
attrNodeName: "attr", //default is 'false'
textNodeName: "#text",
ignoreAttributes: true,
ignoreNameSpace: false,
allowBooleanAttributes: false,
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
localeRange: "", //To support non english character in tag/attribute values.
parseTrueNumberOnly: false,
attrValueProcessor: a => he.decode(a, { isAttributeValue: true }), //default is a=>a
tagValueProcessor: a => he.decode(a) //default is a=>a
*/
export const xml = (config) => {
config = merge(__.xmloptions, config || {});
var Jconfig = merge(config, {
tagValueProcessor: (a) => he.encode(a, { useNamedReferences: true }), // default is a=>a
attrValueProcessor: (a) =>
he.encode(a, { isAttributeValue: isAttribute, useNamedReferences: true }), // default is a=>a
});
const j2x = new parser.j2xParser(config);
const ret = {
toXml: (json) => {
try {
return j2x.parse({ xml: json });
} catch (e) {
if (e.message.indexOf("html.replace") >= 0)
throw new Error("toXml:JSON中的值不能是非字符串内容!");
else throw e;
}
},
toJson: (xml) => {
xml = (xml + "").replace(/(<\?).+\?>/g, "");
!xml.startWith("<xml") && (xml = `<xml>${xml}</xml>`);
return ret.deCDATA(parser.parse(xml), Jconfig);
},
deCDATA: (json) => {
for (var k in json) {
if (json[k][config.cdataTagName])
json[k] = json[k][config.cdataTagName];
else if (typeof json[k] == "object") ret.deCDATA(json[k]);
}
return json.xml;
},
};
return ret;
};
/**
* 生成GUID
*/
export const GUID = function () {
return v4().replace(/\-/g, "");
};
let SnowId = null;
/**
* 生成雪花ID
*/
export const SNOWID = function () {
if (!SnowId)
SnowId = new SnowflakeId({
mid: 42,
offset: (new Date().getFullYear() - 1970) * 31536000 * 1000,
});
return SnowId.generate();
};
export default {
environment,
prop,
link,
desc,
isValid,
getValue,
format,
sb,
showEx,
showException,
include,
random,
hashRandom,
tryC,
tryC2,
watch,
isArray,
once,
whileC,
forC,
each,
finalC,
next,
callback,
callback2,
encHtml,
decHtml,
toJsonString,
json,
merge,
inherits,
create,
create2,
applyCAE,
pris,
hash,
hash2,
toTJson,
getType,
formatPrice,
encodeEmoji,
decodeEmoji,
GUID,
md5,
xhash,
xhmac,
xsign,
xverify,
xcrypt,
xdcrypt,
xml,
xcrypt_a1e,
xdcrypt_a1e,
SHA1PRNG,
SNOWID,
xcryptiv,
xdcryptiv,
deflateBase64,
inflateBase64,
};
//const symbol = Symbol;
const pri = pris();
const __ = {
settings: Symbol("settings"),
exsettings: Symbol("exsettings"),
encreg:
/<|>|~|(\r\n)|!|@|#|\$|%|\^|;|\*|\(|\)|_|\+|\{|\}|\||:|\"|\?|`|\-|=|\[|\]|\\|;|\'|,|\.|\/|,|;|\s/g,
encmatch:
/[a-zA-Z0-9\u4E00-\u9FA5\uF900-\uFA2D]|[\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]|<|>|~|(\r\n)|!|@|#|\$|%|\^|;|\*|\(|\)|_|\+|\{|\}|\||:|\"|\?|`|\-|=|\[|\]|\\|;|\'|,|\.|\/|,|;|\s/g,
encother: {
"(": "%28",
")": "%29",
"*": "%2a",
"'": "%27",
".": "%2e",
"-": "%2d",
_: "%5f",
},
funrep: function (s, o, reg, lreg, rreg) {
return s.replace(reg, function (word) {
const key = "" + word.replace(lreg, "").replace(rreg, "");
return typeof o[key] == "undefined" ? "" : o[key];
});
},
/**
* StringBuilder nodejs版本 用于连续操作字符串对象而不经常移动数组 比较准确快捷的修改字符串内容
*/
StringBuilder: class {
constructor() {
const that = this;
const { _, __ } = pri(that, {
data: [],
length: 0,
append: (str = "") => {
const { _, __ } = pri(that);
__.data.push(str);
__.length += str.length;
},
});
}
get length() {
return pri(this).__.length;
}
append(str) {
const { _, __ } = pri(this);
str = !!str ? __.append(str) : "";
return this;
}
appendFormat(fmt, data) {
return this.append(format(fmt, data));
}
insert(start, data) {
const { _, __ } = pri(this);
const str = _.toString();
__.data = [str.substr(0, start), data, str.substr(start)];
__.length = str.length + data.length;
return this;
}
insertFormat(start, fmt, data) {
this.insert(start, format(fmt, data));
}
remove(start, length) {
const { _, __ } = pri(this);
let str = _.toString();
__.data = [str.substr(0, start), str.substr(start + length)];
__.length = Math.max(0, str.length - length);
return _;
}
toString() {
const { _, __ } = pri(this);
__.data = [__.data.join("")];
return __.data[0];
}
clear() {
let ret = this.toString();
const { _, __ } = pri(this);
__.data = [];
__.length = 0;
return ret;
}
},
showEx: (e) => showEx("", e),
tryHandle: function (errcall = __.showEx) {
return {
apply: function (target, context, proxy) {
try {
return Reflect.apply(...arguments);
} catch (e) {
try {
errcall(e);
} catch (e2) {
__.showEx(e);
}
}
},
};
},
start: null,
emptyfunc: () => true,
sequfunc: async (exp, func, val) => {
let isStop = false;
while (!isStop && val != undefined) {
isStop = true === (await callback2(func, null, val));
val = exp();
}
return true;
},
disorderfunc: (exp, func, val) => {
let data = [];
while (val != undefined) {
data.push(callback2(func, null, val));
val = exp();
}
return Promise.all(data);
},
disorderlfunc: (each, call) => {
while (
!each.isStop &&
each.i <= each.data.length - 1 &&
each.count < each.limit
) {
each.count++;
callback2(each.func, null, each.data[each.i++])
.then(function (ret) {
each.isStop = !!ret;
each.count--;
__.disorderlfunc(each, call);
})
.catch(function (e) {
each.error = e;
each.isStop = true;
each.count--;
__.disorderlfunc(each, call);
});
}
if (each.count <= 0 && (each.isStop || each.i > each.data.length - 1))
call(each.error, true);
return true;
},
disorderlEach: (data = [], func, limit = 1) => {
var each = {
data,
func,
i: 0,
count: 0,
limit,
isStop: false,
error: null,
};
return callback2((call) => {
__.disorderlfunc(each, call);
});
},
disorderffunc: (each, call) => {
while (
!each.isStop &&
each.i <= each.data.length - 1 &&
each.count < each.limit
) {
each.count++;
const val = each.data[each.i++];
callback2(each.func, null, val.k, val.v)
.then(function (ret) {
each.isStop = !!ret;
each.count--;
__.disorderffunc(each, call);
})
.catch(function (e) {
each.error = e;
each.isStop = true;
each.count--;
__.disorderffunc(each, call);
});
}
if (each.count <= 0 && (each.isStop || each.i > each.data.length - 1))
call(each.error, true);
return true;
},
disorderlFor: (data = {}, func, limit = 1) => {
var each = {
data: [],
func,
i: 0,
count: 0,
limit,
isStop: false,
error: null,
};
for (const k in data) {
each.data.push({ k, v: data[k] });
}
return callback2((call) => {
__.disorderffunc(each, call);
});
},
disorderwfunc: (each, call) => {
while (!each.isStop && each.now != null && each.count < each.limit) {
each.count++;
var val = each.now;
each.now = each.exp();
if (val != null)
callback2(each.func, null, val)
.then(function (ret) {
each.isStop = !!ret;
each.count--;
__.disorderwfunc(each, call);
})
.catch(function (e) {
each.error = e;
each.isStop = true;
each.count--;
__.disorderwfunc(each, call);
});
}
if (each.count <= 0 && (each.isStop || each.now == null))
call(each.error, true);
return true;
},
disorderlWhile: (exp, func, limit = 1) => {
var each = { exp, func, i: 0, count: 0, limit, isStop: false, error: null };
return callback2((call) => {
each.now = exp();
__.disorderwfunc(each, call);
});
},
sequEach: (data = [], func) => {
let i = 0;
return __.sequfunc(() => data[i++], func, data[i++]);
},
disorderEach: (data = [], func) => {
var ret = [];
data.forEach((k) => ret.push(callback2(func, null, k)));
return Promise.all(ret);
},
sequFor: async (obj = {}, func) => {
for (const k in obj) {
if (true === (await callback2(func, obj, k, obj[k]))) return true;
}
return true;
},
disorderFor: (obj = {}, func) => {
let data = [];
for (const k in obj) data.push(callback2(func, obj, k, obj[k]));
return Promise.all(data);
},
index: 0,
getTJsonValue: (p, quotation = true) => {
switch (typeof p) {
//case 'number':
//case 'boolean':
// return p;
case "undefined":
return '""';
case "object":
switch (p + "") {
case "null":
return '""';
default:
return quotation
? '"' +
(p + "").replace(/['"\\]/g, function (v) {
return "\\" + v;
}) +
'"'
: "" + p;
}
default:
return quotation
? '"' +
(p + "").replace(/['"\\]/g, function (v) {
return "\\" + v;
}) +
'"'
: "" + p;
}
},
clone: (source) => {
switch (getType(source)) {
case "Object":
case "object":
return __.merge({}, source);
case "array":
case "Array":
const aim = [];
for (const i in source) {
aim.push(__.clone(source[i]));
}
return aim;
default:
return source;
}
},
merge: (aim, source) => {
//tochange VJ's merge
if (!(typeof source == "object" && !isArray(source))) {
return aim;
}
for (const i in source) {
if (source[i] !== undefined) {
if (!isValid(aim[i])) {
aim[i] = __.clone(source[i]);
} else {
switch (getType(aim[i])) {
case "object":
case "Object":
__.merge(aim[i], source[i]);
break;
case "Array":
//处理数组
let hasmergeIndex = false;
for (
let i3 = 0, k = source[i][i3];
i3 < source[i].length;
i3++, k = source[i][i3]
) {
if (k === null || k === undefined) continue;
if (typeof k.mergeIndex == "number") {
hasmergeIndex = true;
if (aim[i].length < k.mergeIndex + 1) {
aim[i].push(k);
} else {
aim[i][i3] = __.merge(aim[i][i3], k);
}
} else if (typeof k.moveIndex == "number") {
hasmergeIndex = true;
aim[i].splice(k.moveIndex, 0, k);
}
}
if (!hasmergeIndex) {
aim[i] = __.clone(source[i]);
}
break;
default:
aim[i] = source[i];
break;
}
}
}
}
return aim;
},
/**
* 从base64 转成 binary
*/
convert2Binary: (str) => {
return Buffer.from(str, "base64").toString("binary");
},
/**
* 从string 转成 base64
*/
convert2Base64: (str) => {
var buffer;
if (str instanceof Buffer) {
buffer = str;
} else {
buffer = Buffer.from(str.toString(), "binary");
}
return buffer.toString("base64");
},
include: {},
unclude: {},
xmloptions: {
attributeNamePrefix: "@_",
attrNodeName: "attr", //default is 'false'
textNodeName: "#text",
ignoreAttributes: true,
ignoreNameSpace: false,
allowBooleanAttributes: false,
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
localeRange: "", //To support non english character in tag/attribute values.
parseTrueNumberOnly: false,
attrValueProcessor: (a) => he.decode(a, { isAttributeValue: true }), //default is a=>a
tagValueProcessor: (a) => he.decode(a), //default is a=>a
},
};
{
//日期函数处理
Date.prototype.DIC = {
y: "FullYear",
q: "Month",
m: "Month",
w: "Date",
d: "Date",
h: "Hours",
n: "Minutes",
s: "Seconds",
ms: "MilliSeconds",
};
Date.prototype.add = function (interval, number) {
var d = new Date(this.getTime());
var k = Date.prototype.DIC;
var n = { q: 3, w: 7 };
k[interval]
? d["set" + k[interval]](
Math.A(d["get" + k[interval]](), Math.X(n[interval] || 1, number)),
)
: (function () {
throw new Error("interval参数不是支持的类型:" + toJsonString(k));
})();
return d;
};
/* 计算两日期相差的日期年月日等 new Date().diff('h',new Date().add('d',1)); */
Date.prototype.diff = function (interval, objDate2) {
const d = this,
i = {},
t = d.getTime(),
t2 = objDate2.getTime();
i["y"] = objDate2.getFullYear() - d.getFullYear();
i["q"] =
i["y"] * 4 +
Math.floor(objDate2.getMonth() / 4) -
Math.floor(d.getMonth() / 4);
i["m"] = i["y"] * 12 + objDate2.getMonth() - d.getMonth();
i["ms"] = objDate2.getTime() - d.getTime();
// i['w'] = Math.floor((t2 + 345600000) / (604800000)) - Math.floor((t + 345600000) / (604800000));
// i['d'] = Math.floor(t2 / 86400000) - Math.floor(t / 86400000);
// i['h'] = Math.floor(t2 / 3600000) - Math.floor(t / 3600000);
// i['n'] = Math.floor(t2 / 60000) - Math.floor(t / 60000);
// i['s'] = Math.floor(t2 / 1000) - Math.floor(t / 1000);
i["w"] = Math.floor(Math.D(Math.S(t2, t), 604800000.0));
i["d"] = Math.floor(Math.D(Math.S(t2, t), 86400000.0));
i["h"] = Math.floor(Math.D(Math.S(t2, t), 3600000.0));
i["n"] = Math.floor(Math.D(Math.S(t2, t), 60000.0));
i["s"] = Math.floor(Math.D(Math.S(t2, t), 1000.0));
return i[interval];
};
/* 计算两日期相差的日期年月日等 new Date().diff('h',new Date().add('d',1)); */
Date.prototype.sub = function (interval, objDate2) {
return Date.prototype.diff.apply(objDate2, [interval, this]);
};
/* 计算两日期相差的日期年月日等 new Date().toString('yyyy-MM-dd'); */
Date.prototype.toString = function (fmt) {
const o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, //小时
"H+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
S: this.getMilliseconds(), //毫秒
};
const week = {
0: "/u65e5",
1: "/u4e00",
2: "/u4e8c",
3: "/u4e09",
4: "/u56db",
5: "/u4e94",
6: "/u516d",
};
if (fmt) {
} else {
fmt = "yyyy/MM/dd HH:mm:ss";
}
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
(this.getFullYear() + "").substr(4 - RegExp.$1.length),
);
}
if (/(E+)/.test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
(RegExp.$1.length > 1
? RegExp.$1.length > 2
? "/u661f/u671f"
: "/u5468"
: "") + week[this.getDay() + ""],
);
}
for (const k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 1
? o[k]
: ("00" + o[k]).substr(("" + o[k]).length),
);
}
}
return fmt;
};
//字符串函数扩展
String.prototype.endWith = String.prototype.endsWith;
String.prototype.startWith = function (str) {
if (
str == null ||
str == "" ||
this.length == 0 ||
str.length > this.length
)
return false;
if (this.substr(0, str.length) == str) return true;
else return false;
};
String.prototype.startsWith =
String.prototype.startsWith || String.prototype.startWith;
String.prototype.eq = function (str = "", isOri) {
str = str + "";
return isOri ? this == str : this.toLowerCase() == str.toLowerCase();
};
String.prototype.trim = function (chr) {
switch (chr) {
case "/":
case "\\":
case "?":
case "[":
case "]":
case ".":
case "*":
case "(":
case ")":
case "{":
case "}":
case "|":
case "^":
case "$":
case "+":
chr = "\\" + chr;
break;
}
return this.replace(
isValid(chr)
? new RegExp("(^(" + chr + ")+)|((" + chr + ")+$)", "g")
: /(^\s+)|(\s+$)/g,
"",
);
};
/**
* 高精度 加法
*/
Math.A = function (...args) {
var a = new Decimal(0);
args.forEach((v) => (a = a.add(v)));
return a.toNumber();
};
/**
* 高精度 减法
*/
Math.S = function (...args) {
var a = new Decimal(args[0]);
args.slice(1).forEach((v) => (a = a.sub(v)));
return a.toNumber();
};
/**
* 高精度 乘法
*/
Math.X = function (...args) {
var a = new Decimal(1);
args.forEach((v) => (a = a.mul(v)));
return a.toNumber();
};
/**
* 高精度 除法
*/
Math.D = function (...args) {
var a = new Decimal(args[0]);
args.slice(1).forEach((v) => (a = a.div(v)));
return a.toNumber();
};
}