用户:小苏打_查看:0 回复:4 评论:0 创建时间:2024-08-05T00:22:58
/**
* 得到更好的控制台输出
* - 清晰的层级显示,让输出更美观
* - 自动展开对象、数组,让debug更简单
* - 自定义最大展开深度、最大长度、占位符、tab字符等
* - 循环引用检测
* @example Rich.print(obj)
* @todo 稀疏数组支持
*/
class Rich {
static config = {
maxDepth: 5,
maxLength: 40,
placeholder: '(...)',
tabChar: '|---'
};
static handlers = [
{
condition: obj => obj === null,
handler: () => 'null',
},
{
condition: obj => obj === undefined,
handler: () => 'undefined'
},
{
condition: obj => typeof obj === 'string',
handler: obj => obj,
cat: true
},
{
condition: obj => typeof obj === 'number'
|| typeof obj === 'bigint'
|| typeof obj === 'boolean'
|| typeof obj === 'symbol',
handler: obj => obj.toString(),
cat: true
},
{
condition: (_, depth) => depth >= Rich.config.maxDepth,
handler: _ => '...'
},
{
condition: obj => obj instanceof Array,
handler: (obj, depth, fn) => '[' + obj.map(v => fn(v, depth)).join(', ') + ']'
},
{
condition: obj => obj instanceof Date,
handler: obj => obj.toISOString()
},
{
condition: obj => obj instanceof Function,
handler: obj => `Function ${obj.name}`
},
{
condition: obj => obj instanceof Object,
handler: (obj, depth, fn) => {
if (Rich.visitedObj.has(obj)) {
return '(Circular Reference)';
}
Rich.visitedObj.add(obj);
const keys = Object.keys(obj);
if (keys.length == 0) {
return '{}';
}
const ctxTab = Rich.config.tabChar.repeat(depth + 1);
const ctx = keys
.map(key => `${key}: ${fn(obj[key], depth + 1)}`)
.join(`,\n${ctxTab}`);
Rich.visitedObj.delete(obj);
return `{\n${ctxTab}${ctx}\n${Rich.config.tabChar.repeat(depth)}}`;
}
}
];
static visitedObj = new WeakSet();
static getRiched(obj, depth = 0) {
for (const handler of Rich.handlers) {
if (!handler.condition(obj, depth)) {
continue;
}
let ctx = handler.handler(obj, depth, Rich.getRiched);
if (handler.cat && ctx.length >= Rich.config.maxLength) {
ctx = ctx.slice(0, Rich.config.maxLength / 2) + '...' + ctx.slice(-Rich.config.maxLength / 2);
}
return ctx;
}
return `${typeof obj}(${obj.toString() ?? '...'})`;
}
static print(obj) {
console.log(Rich.getRiched(obj));
}
}
exports.Rich = Rich;示例用法:
const obj = {
a: {
c: {
f: 123,
g: [3, 3, null, 4, 5],
h: 2n**1024n
},
i: "A quick brown fox jumps over a lazy dog."
}
}
Rich.print(obj);
输出效果(注:由于box3控制台会合并所有空格,只能使用一些字符撑起宽度。可以在Rich.config中配置替代字符。):
{
|---a: {
|---|---c: {
|---|---|---f: 123,
|---|---|---g: [3, 3, null, 4, 5],
|---|---|---h: 179769313486231...329624224137216
|---|---},
|---|---i: A quick brown f...ver a lazy dog.
|---}
}
typescript源文件:
interface ConvertHandler {
condition: (obj: any, depth: number) => boolean;
handler: (obj: any, depth: number, fn: (obj: any, depth: number) => string) => string;
cat?: boolean
}
interface RichConfig {
maxDepth: number;
maxLength: number;
placeholder: string;
tabChar: string;
}
/**
* 得到更好的控制台输出
* @example Rich.print(obj)
* @todo 稀疏数组支持
*/
export abstract class Rich {
static config: RichConfig = {
maxDepth: 5,
maxLength: 30,
placeholder: '(...)',
tabChar: '|---'
};
static handlers: ConvertHandler[] = [
{
condition: obj => obj === null,
handler: () => 'null',
},
{
condition: obj => obj === undefined,
handler: () => 'undefined'
},
{
condition: obj => typeof obj === 'string',
handler: obj => obj,
cat: true
},
{
condition: obj => typeof obj === 'number'
|| typeof obj === 'bigint'
|| typeof obj === 'boolean'
|| typeof obj === 'symbol',
handler: obj => obj.toString(),
cat: true
},
{
condition: (_, depth) => depth >= Rich.config.maxDepth,
handler: _ => '...'
},
{
condition: obj => obj instanceof Array,
handler: (obj, depth, fn) => '[' + (obj as Array<any>).map(v => fn(v, depth)).join(', ') + ']'
},
{
condition: obj => obj instanceof Object,
handler: (obj, depth, fn) => {
const ctxTab = Rich.config.tabChar.repeat(depth+1);
const ctx = Object.keys(obj)
.map(key => `${key}: ${fn(obj[key], depth + 1)}`)
.join(`,\n${ctxTab}`);
return `{\n${ctxTab}${ctx}\n${Rich.config.tabChar.repeat(depth)}}`;
}
}
]
static getRiched(obj: any, depth: number = 0): string {
for (const handler of Rich.handlers) {
if(!handler.condition(obj, depth)){
continue;
}
let ctx = handler.handler(obj, depth, Rich.getRiched);
if(handler.cat && ctx.length >= Rich.config.maxLength){
ctx = ctx.slice(0, Rich.config.maxLength / 2) + '...' + ctx.slice(-Rich.config.maxLength / 2);
}
return ctx;
}
return `${typeof obj}(${obj.string})`;
}
static print(obj: any){
console.log(Rich.getRiched(obj));
}
}点赞0
评论