# js-log-lib

## 介绍

浏览器和 node 共用的 log 样式，行为控制工具，可以自定义输出样式，其核心原理是采用了 ANSI 指令以及 css 属性，更多用法可以参照 ANSI 的详细介绍

## 调试说明

1.  pnpm build（构建）
2.  pnpm dev（node 中调试源码）
3.  pnpm dev:umd（浏览器中调试）
4.  在 esm，cjs，window 环境下导入该工具库
5.  详情见 dev 文件夹

## 参与贡献

1.  Fork 本仓库
2.  Star 仓库
3.  提交代码
4.  新建 Pull Request

## 使用说明

### 安装

`npm install js-log-lib`
或
`yarn add js-log-lib`
或
`pnpm install js-log-lib`

### 引入

#### ESM

```javascript
import { JSLog } from "js-log-lib";
```

#### CJS

```javascript
const { JSLog } = require("js-log-lib");
```

#### 浏览器中

```html
<script src="./node_modules/js-log-lib/dist/umd/index.js"></script>
<script>
  console.log(JSLog);
</script>
```

### 开始使用

在浏览器环境下和 Node 环境下稍有区别

建议在使用前仔细阅读 types.ts 和 static.ts 文件，这样有助于理解和使用

static.ts https://gitee.com/DieHunter/js-log-lib/blob/master/src/static.ts 文件下存放静态变量，大部分指令都在这
types.ts https://gitee.com/DieHunter/js-log-lib/blob/master/src/types.ts 是 JSLog 的核心类型，一些函数的配置项可以在这找到

#### 创建 JSLog 实例

```javascript
const logger = new JSLog();
```

#### 全局配置项

参照 types.ts 中的 IGlobalOpts 类型
全局配置项可以传入以下属性

```typescript
type IGlobalOpts = Partial<{
  text: string; // 要打印的文本
  reset: boolean; // 是否在末尾重置样式
  type: string; // console的类型
  split: boolean; // 是否拆分显示，在node中可以在一个console.log中分开显示，比如：console.log("1","2","3")和console.log("123")，前者在字符之间会有空格，split为true表示使用前者显示，反之使用后者，在浏览器环境下只能合并显示
  color: IColor[] | IColor; // 前（后）景色或其数组，方便传入多个颜色参数，但是有些控制台似乎不兼容
  textStyle: ITextStyle[] | ITextStyle; // 文本样式或样式数组
  cursor: ICursor; // 光标控制
  move: IMoveParams; // 光标移动参数
  scroll: number; // 滚动条行数
  style: Partial<CSSStyleDeclaration>; // CSS样式对象，仅支持浏览器环境
}>;
```

#### 默认配置

在 index 中，defaultOpts 是默认配置，当开发者没有设置 option 时，会使用这里的样式和设置

```typescript
const defaultOpts: IGlobalOpts = {
  reset: true,
  type: "log",
  split: true,
};
```

#### 基本使用

##### 1. 打印字符

```typescript
const logger = new JSLog();
logger.log({ text: "阿宇的编程之旅" }); // 阿宇的编程之旅
```

##### 2. 为当前实例添加全局配置项

```typescript
// 全局配置的增加方式有两种，一是在实例化对象时传入构造函数，第二种是通过 mixins 添加
const logger = new JSLog({ type: "error", color: "red" });
logger.log({ text: "我是个错误提示" });
logger.mixins({ type: "info", color: "green" });
logger.log({ text: "我是个成功提示" });
```

##### 3. 清空所有样式及操作行为

```typescript
const logger = new JSLog({ type: "error", color: "red" });
logger.log({ text: "阿宇" });
logger.clear();
logger.log({ text: "阿宇" });
```

##### 4. 校验传入的参数是否允许

```typescript
const logger = new JSLog();
// node中
logger.checkOptions({ style: {} }); // node环境下无法使用style相关属性
```

##### 5. 样式调整

Node 环境中

```typescript
// 在node环境下使用color控制文字的前（后）景色，使用textStyle控制文字形态样式，如加粗，斜体等（不同的控制台对样式兼容性不相同，可能会导致冲突或失效问题）
// 样式的调整实际上是使用ANSI编码完成的，其指令集可以参照 static.ts 中的ANSIParams变量，其中color和textStyle表示的就是对于的操作
const logger = new JSLog();
logger.log({
  text: "hello world",
  color: "cyan", // 字体青色
  textStyle: "bold", // 加粗
});
```

浏览器环境中

```typescript
// 浏览器环境下也可以使用color，textStyle控制文字样式，但是使用style属性可以支持更多的样式设置，具体可以参考CSSStyleDeclaration类型，如果style与上述的color，textStyle同时设置了，可能会导致样式冲突
logger.log({
  text: "hello world",
  style: { color: "lightblue", background: "#333", margin: "10px" },
});
```

##### 6. 光标控制指令

```typescript
// 光标控制只支持在Node环境下使用，和样式调整类似，其原理也是使用ANSI编码在控制台输出对应指令来完成的，同样参照 static.ts 中的ANSIParams变量，cursor就是光标指令
const logger = new JSLog();
logger.log({ text: "i m here" });
logger.log({ text: "i m here" });
logger.log({ text: "i m here", cursor: "eraseDisplay" }); // 清除屏幕
```

##### 7. 光标位置偏移

```typescript
// 光标移动与上述的光标指令相同，只不过在指令中传入了移动距离
const logger = new JSLog();
logger.log(
  {
    move: {
      direct: "right",
      position: 5,
    },
    text: "编程之旅", // 先打印后面的字符
  },
  {
    move: {
      direct: "left",
      position: 14,
    },
    text: "阿宇的", // 将前面的字符插入到左边
  }
);
// 输出：阿宇的编程之旅
```

##### 8. 滚动条控制

```typescript
// 借助TimerManager定时器，或者setinterval实现一个向上滑动滚动条的效果，每500毫秒打印一次行数
import { TimerManager } from "utils-lib-js";
const logger = new JSLog();
const timerManager = new TimerManager();
let scroll = 0;
const timer = timerManager.add(() => {
  if (scroll <= -5) return timerManager.delete(timer);
  scroll--;
  logger.log({ text: scroll.toString(), scroll });
}, 500);
```

#### 其他用法

##### 1. log 的链式调用

```typescript
const logger = new JSLog();
logger.log({ text: "hello" }).log({ text: "world" });
```

##### 2. 在同一行打印多种类型 log

```typescript
const logger = new JSLog({ split: false });
logger.log(
  { text: "阿宇", color: "red" },
  { text: "的编程", color: "brightCyan" },
  { text: "之旅", color: "bgBrightMagenta" }
);
```

##### 3. 属性的指令集

```typescript
// 上面我们提到了options可以传入一种指令控制样式或者行为，某些属性支持传入一个指令集，达到样式批量生效的效果
logger.log({
  text: "hello world",
  color: ["red", "bgBrightGreen"], // 红色字体，亮绿背景
  textStyle: ["bold", "italic", "strikethrough"], // 加粗，斜体，删除线
});
```

##### 4.JSLog 中针对 ANSI 的一些快捷操作

如果你了解 ANSI 编码的指令，那么下面的函数可以让你锦上添花

不了解也没关系，在 static 文件下我已经将常用的 ANSI 列出，以供参考使用

1. ANSI 编码指令拼接

```typescript
// 通过getANSI和ANSI编码达到控制样式的效果，使用console或者直接使用JSLog直接输出getANSI的转移字符可以设置对应的指令
const logger = new JSLog();
const { getANSI } = logger;
console.log(getANSI(`35`), "hello world"); // 输出紫色的字符串
logger.log({
  text: getANSI(`34`) + "hello world",
}); // 输出蓝色的字符串
```

2. 颜色设置

```typescript
//如果你不了解ANSI也没关系，JSLog提供了一套语义化的配置函数，使用下面的getColor函数可以设置对应的颜色样式
const logger = new JSLog();
const { getANSI, getColor } = logger;
logger.log({
  text: getANSI(getColor("bgBlue")) + "hello world",
}); // 输出蓝色背景的字符串
```

3. 字体样式

```typescript
// 使用下面的getTextStyle函数可以设置对应的字体样式
const logger = new JSLog();
const { getANSI, getTextStyle } = logger;
logger.log({
  text: getANSI(getTextStyle("bold")) + "hello world",
}); // 输出加粗效果的字符串
```

4. 光标操作

```typescript
// 使用getCursor函数可以进行光标相关的操作
const logger = new JSLog();
const { getANSI, getCursor } = logger;
logger.log(
  { text: "----------------------------" },
  {
    text: getANSI(getCursor("toLineStart"), false) + "hello world",
  }
); //移动到行首并输出字符
```

5. 光标移动

```typescript
// 使用moveTo函数可以移动光标
const logger = new JSLog();
const { getANSI, moveTo } = logger;
logger.log(
  { text: "hello" },
  {
    text: getANSI(moveTo({ direct: "right", position: 5 }), false) + "world",
  }
); //向右移动5次光标
```

6. 滚动条移动

```typescript
// 使用scrollTo函数可以移动滚动条
const logger = new JSLog();
const { getANSI, scrollTo } = logger;
logger.log({
  text: getANSI(scrollTo(-2), false) + "hello world",
}); //向上移动2行滚动条
```

7. 重置样式

```typescript
// 通过运行reset函数可以重置样式，由于jslog默认配置了reset参数，所以样式只会在一个log队列中生效，要取消重置可以在实例化时传入reset: false，这里我直接使用console.log展示效果
const logger = new JSLog();
const { getANSI, getColor, reset } = logger;
console.log(
  getANSI(getColor("bgBrightGreen")),
  "i m bgBrightGreen",
  reset(),
  "i m reset"
);
```

##### 5. ANSI 颜色指令的进阶用法

上面说到了前后景色的设置，使用 color 属性可以对 log 的字符设置对应的颜色属性，然而由于颜色的指令数有限，有许多其他颜色无法表示，所以 ANSI 提供了两种设置颜色参数的方式

1. 第一种是 256 种色调色板的形式，又叫做兼容模式，设置该模式需要将 ANSI 的第二个参数 mode 设置为 5 ：

```typescript
const ANSI = `\x1B[38;5;<color>m`;
```

它支持设置数字 0-255：
0-15 是标准颜色，也就是之前用到的颜色变量
16-231 有 216 种颜色，这些颜色按照六阶的 RGB 立方体规则排列，提供了各种颜色的组合
232-255 是灰度颜色，这些颜色表示不同灰度级别，从黑到白。232 表示最暗的灰色，255 表示最亮的灰色。
通过下面的代码我们可以打印出全部 256 种色阶：

```typescript
const logger = new JSLog();
const { getANSI, getRGB, reset } = logger;
let color = ``;
for (let i = 0; i < 255; i++) {
  color += `${getANSI(
    getRGB({ color: i, mode: "compatibility", type: "background" })
  )}  `;
}
console.log(color, reset());
```

2. 另一种设置颜色的方式是使用 True Color（真彩色）模式。在 True Color 模式下，可以通过指定 RGB（红绿蓝）值来准确设置颜色，而不仅仅依赖于预定义的颜色索引，就像是 css 中的 rgb 方法。该模式需要将 ANSI 的第二个参数 mode 设置为 2：

```typescript
const ANSI = `\x1B[38;2;<r>;<g>;<b>m`;
```

它支持设置数字 256^3 种（16777216 种颜色），在真彩模式下可以通过指定每个颜色通道的具体强度值来准确定义颜色

```typescript
const logger = new JSLog();
logger.log(
  { text: "hello", color: { red: 255 } },
  {
    text: "阿宇的",
    color: { green: 255 },
  },
  { text: "编程之旅", color: { blue: 255, type: "background" } }
);
```

##### 6. 光标坐标轴移动

通过配置 move 参数可以实现坐标位移的功能

```typescript
// 下面的代码中我们实现了一个斜着输出字符串的功能
import { TimerManager } from "utils-lib-js";
const logger = new JSLog();
const timer = new TimerManager(); // 创建定时器
const str = "hello world";
const position = {
  row: 0, // 行
  col: 0, // 列
};
logger.log({ cursor: "eraseDisplay" }); // 清屏
timer.add(() => {
  const _str = str[position.col];
  if (!_str) timer.clear();
  position.col++;
  position.row++;
  move(_str);
}, 100);

const move = (str) =>
  logger.log({
    text: str,
    move: {
      direct: "custom",
      position,
    },
  });
```
