@whitesev/utils
Version:
一个常用的工具库
234 lines (229 loc) • 7.7 kB
text/typescript
import type { UtilsLogOptions } from "./types/Log";
export class Log {
/** 是否禁用输出的flag */
#disable: boolean = false;
/** 前面的TAG标志 */
tag: string = "Utils.Log";
/* 使用的console函数 */
#console: Console = null as any;
/* 当前输出的数量 */
#logCount = 0;
/* 配置 */
#details: UtilsLogOptions = {
tag: true,
successColor: "background: #0eac0eff;",
errorColor: "background: #FF0000;",
infoColor: "background: #6495ed;",
warnColor: "background: #ff8c00;",
debug: false,
autoClearConsole: false,
logMaxCount: 999,
};
/**
* 通用样式配置
*/
#commonStyleConfig = {
commonStyle: "color: #ffffff; padding: 3px; border-radius: 3px;line-height: 1;margin-right: 6px;",
tagStyle: "background: #6495ed;",
callerNameStyle: "background: #78909C;",
};
/**
* @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[]) {
const result = {
name: "",
position: "",
};
for (let stackString of stack) {
stackString = stackString.trim();
const stackFunctionNameMatch = stackString.match(/^at[\s]+(.+?)[\s]+/i);
const stackFunctionNamePositionMatch = stackString.match(/^at[\s]+.+[\s]+\((.+?)\)/i);
if (stackFunctionNameMatch == null) {
continue;
}
if (stackFunctionNamePositionMatch == null) {
continue;
}
/* 获取最后一个,因为第一个是包含了at */
const stackFunctionName = stackFunctionNameMatch[stackFunctionNameMatch.length - 1];
const 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 === "") {
const lastStackString = stack[stack.length - 1].trim();
if (lastStackString.startsWith("at chrome-extension://")) {
const 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 tagColor tag颜色
*/
private printContent(msg: any[], tagColor?: string) {
this.checkClearConsole();
const stackSplit = new Error()!.stack!.split("\n");
stackSplit.splice(0, 2);
const { name: callerName, position: callerPosition } = this.parseErrorStack(stackSplit);
const tagName = this.tag;
const that = this;
const msgColorDetails: string[] = [];
// 控制台输出的tag的html格式
let consoleHTML = `%c${tagName}`;
/** tag的html输出格式 */
if (typeof tagColor === "string" && tagColor.trim() !== "") {
msgColorDetails.push(that.#commonStyleConfig.commonStyle + tagColor);
} else {
msgColorDetails.push(that.#commonStyleConfig.commonStyle + that.#commonStyleConfig.tagStyle);
}
// 调用的函数名的html输出格式
if (callerName.trim() == "") {
// 无调用函数名
} else {
consoleHTML = `${consoleHTML}%c${callerName}`;
msgColorDetails.push(that.#commonStyleConfig.commonStyle + that.#commonStyleConfig.callerNameStyle);
}
if (Array.isArray(msg)) {
that.#console.log(`${consoleHTML}`, ...msgColorDetails, ...msg);
} else {
that.#console.log(`${consoleHTML}`, ...msgColorDetails, 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;
// , "background: #FEF6D5;padding: 4px 6px 4px 0px;"
this.printContent(args, this.#details.warnColor);
}
/**
* 控制台-错误输出
* @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();
const stack = new Error()!.stack!.split("\n");
stack.splice(0, 1);
const errorStackParse = this.parseErrorStack(stack);
/** 堆栈函数名 */
const stackFunctionName = errorStackParse.name;
/** 堆栈位置 */
const stackFunctionNamePosition = errorStackParse.position;
const callerName = stackFunctionName;
const msgColorDetails: string[] = [
`${this.#commonStyleConfig.commonStyle + this.#details.infoColor}`,
`${this.#commonStyleConfig.commonStyle + this.#commonStyleConfig.callerNameStyle}`,
];
this.#console.log(`%c${this.tag}%c${callerName}%c`, msgColorDetails);
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;
}
}