@whitesev/utils
Version:
一个常用的工具库
278 lines (272 loc) • 7.51 kB
text/typescript
import type { UtilsLogOptions } from "./types/Log";
class Log {
/** 是否禁用输出的flag */
#disable: boolean = false;
/** 前面的TAG标志 */
tag: string = "Utils.Log";
/* 使用的console函数 */
#console: Console = null as any;
/* 当前输出的数量 */
#logCount = 0;
/* 配置 */
#details: UtilsLogOptions = {
tag: true,
successColor: "#0000FF",
errorColor: "#FF0000",
infoColor: "0",
warnColor: "0",
debug: false,
autoClearConsole: false,
logMaxCount: 999,
};
/**
* 颜色配置
*/
#msgColorDetails = [
"font-weight: bold; color: cornflowerblue",
"font-weight: bold; color: cornflowerblue",
"font-weight: bold; color: darkorange",
"font-weight: bold; color: cornflowerblue",
];
/**
* @param __GM_info 油猴管理器的API GM_info,或者是一个对象,如{"script":{name:"Utils.Log"}},或者直接是一个字符串,用作tag名
* @param console 可指定console对象为unsafeWindow下的console或者是油猴window下的console
*/
constructor(
__GM_info?:
| {
script: {
name: string;
};
}
| string,
console: Console = window.console
) {
if (typeof __GM_info === "string") {
this.tag = __GM_info;
} else if (
typeof __GM_info === "object" &&
typeof __GM_info?.script?.name === "string"
) {
this.tag = __GM_info.script.name;
}
this.#console = console;
}
/**
* 解析Error的堆栈获取实际调用者的函数名及函数所在的位置
* @param stack
*/
private parseErrorStack(stack: string[]) {
let result = {
name: "",
position: "",
};
for (let stackString of stack) {
stackString = stackString.trim();
let stackFunctionNameMatch = stackString.match(/^at[\s]+(.+?)[\s]+/i);
let stackFunctionNamePositionMatch = stackString.match(
/^at[\s]+.+[\s]+\((.+?)\)/i
);
if (stackFunctionNameMatch == null) {
continue;
}
if (stackFunctionNamePositionMatch == null) {
continue;
}
/* 获取最后一个,因为第一个是包含了at */
let stackFunctionName =
stackFunctionNameMatch[stackFunctionNameMatch.length - 1];
let stackFunctionNamePosition =
stackFunctionNamePositionMatch[
stackFunctionNamePositionMatch.length - 1
];
if (
stackFunctionName === "" ||
stackFunctionName.match(
/^(Utils\.|)Log(\.|)|.<anonymous>$|^Function.each|^NodeList.forEach|^k.fn.init.each/g
)
) {
continue;
} else {
result.name = stackFunctionName;
result.position = stackFunctionNamePosition;
break;
}
}
if (result.position === "") {
let lastStackString = stack[stack.length - 1].trim();
if (lastStackString.startsWith("at chrome-extension://")) {
let lastStackMatch = lastStackString.match(/^at[\s]+(.+)/);
if (lastStackMatch) {
result.position = lastStackMatch[lastStackMatch.length - 1];
}
}
}
if (result.position === "") {
result.position = stack[stack.length - 1].trim().replace(/^at[\s]*/g, "");
}
return result;
}
/**
* 检测清理控制台
*/
private checkClearConsole() {
this.#logCount++;
if (
this.#details.autoClearConsole &&
this.#logCount > this.#details.logMaxCount
) {
this.#console.clear();
this.#logCount = 0;
}
}
/**
* 输出内容
* @param msg 需要输出的内容
* @param color 颜色
* @param otherStyle 其它CSS
*/
private printContent(msg: any[], color: string, otherStyle?: string) {
this.checkClearConsole();
otherStyle = otherStyle || "";
let stackSplit = new Error()!.stack!.split("\n");
stackSplit.splice(0, 2);
let { name: callerName, position: callerPosition } =
this.parseErrorStack(stackSplit);
let tagName = this.tag;
let that = this;
/** tag的html输出格式 */
let tagNameHTML = `%c[${tagName}%c`;
/** 调用的函数名的html输出格式 */
let callerNameHTML = `%c${callerName}%c]%c`;
callerName.trim() !== "" && (callerNameHTML = "-" + callerNameHTML);
/**
* 输出消息到控制台
* @param message
*/
function consoleMsg(message: any) {
if (typeof message === "string") {
that.#console.log(
`${tagNameHTML}${callerNameHTML} %s`,
...that.#msgColorDetails,
`color: ${color};${otherStyle}`,
message
);
} else if (typeof message === "number") {
that.#console.log(
`${tagNameHTML}${callerNameHTML} %d`,
...that.#msgColorDetails,
`color: ${color};${otherStyle}`,
message
);
} else if (typeof message === "object") {
that.#console.log(
`${tagNameHTML}${callerNameHTML} %o`,
...that.#msgColorDetails,
`color: ${color};${otherStyle}`,
message
);
} else {
that.#console.log(message);
}
}
if (Array.isArray(msg)) {
for (let index = 0; index < msg.length; index++) {
consoleMsg(msg[index]);
}
} else {
consoleMsg(msg);
}
if (this.#details.debug) {
/* 如果开启调试模式,输出堆栈位置 */
this.#console.log(callerPosition);
}
}
/**
* 控制台-普通输出
* @param args 需要输出的内容
* @example
* log.info("输出信息","输出信息2","输出信息3","输出")
*/
info(...args: any[]) {
if (this.#disable) return;
this.printContent(args, this.#details.infoColor);
}
/**
* 控制台-警告输出
* @param args 需要输出的内容
* @example
* log.warn("输出警告","输出警告2","输出警告3","输出警告4")
*/
warn(...args: any[]) {
if (this.#disable) return;
this.printContent(
args,
this.#details.warnColor,
"background: #FEF6D5;padding: 4px 6px 4px 0px;"
);
}
/**
* 控制台-错误输出
* @param args 需要输出的内容
* @example
* log.error("输出错误","输出错误2","输出错误3","输出错误4")
*/
error(...args: any[]) {
if (this.#disable) return;
this.printContent(args, this.#details.errorColor);
}
/**
* 控制台-成功输出
* @param args 需要输出的内容
* @example
* log.success("输出成功")
*/
success(...args: any[]) {
if (this.#disable) return;
this.printContent(args, this.#details.successColor);
}
/**
* 控制台-输出表格
* @param msg 需要输出的内容
* @example
* log.table([{"名字":"example","值":"123"},{"名字":"example2","值":"345"}])
*/
table(msg: any[]) {
if (this.#disable) return;
this.checkClearConsole();
let stack = new Error()!.stack!.split("\n");
stack.splice(0, 1);
let errorStackParse = this.parseErrorStack(stack);
/** 堆栈函数名 */
let stackFunctionName = errorStackParse.name;
/** 堆栈位置 */
let stackFunctionNamePosition = errorStackParse.position;
let callerName = stackFunctionName;
this.#console.log(
`%c[${this.tag}%c-%c${callerName}%c]%c`,
...this.#msgColorDetails,
`color: ${this.#details.infoColor};`
);
this.#console.table(msg);
if (this.#details.debug) {
this.#console.log(stackFunctionNamePosition);
}
}
/**
* 配置Log对象的颜色
* @param paramDetails 配置信息
*/
config(paramDetails: Partial<UtilsLogOptions>) {
this.#details = Object.assign(this.#details, paramDetails);
}
/** 禁用输出 */
disable() {
this.#disable = true;
}
/** 恢复输出 */
recovery() {
this.#disable = false;
}
}
export { Log };