npm package: @knotx/utils
Description: Utils for Knotx
Author: boenfu
Latest version: 0.5.10

# @knotx/utils

Knotx 工具函数库，提供一系列实用工具函数，包括 BEM 命名约定、ID 生成、数据操作处理以及符号工具等。

## 安装

```bash
npm install @knotx/utils
```

```bash
yarn add @knotx/utils
```

```bash
pnpm add @knotx/utils
```

## 概述

`@knotx/utils` 是 Knotx 生态系统中的核心工具函数库，提供了以下主要功能：

- **BEM 命名约定工具**：帮助生成符合 BEM 规范的 CSS 类名
- **ID 生成工具**：生成唯一标识符
- **数据操作工具**：提供数据操作相关的工具函数
- **符号工具**：创建和管理符号标识符

## API 文档

### BEM 工具函数

#### `bem(block, element?, modifier?, prefix?)`

根据 BEM 命名约定生成 CSS 类名。

**参数：**
- `block` (string): 块名
- `element` (string, 可选): 元素名
- `modifier` (string, 可选): 修饰符名
- `prefix` (string, 可选): 前缀，默认为 `'knotx-'`

**返回值：**
- `string`: 生成的 CSS 类名

**示例：**

```javascript
import { bem } from '@knotx/utils'

// 基础块
bem('button')
// 输出: 'knotx-button'

// 块 + 元素
bem('button', 'text')
// 输出: 'knotx-button__text'

// 块 + 修饰符
bem('button', undefined, 'primary')
// 输出: 'knotx-button--primary'

// 块 + 元素 + 修饰符
bem('button', 'text', 'large')
// 输出: 'knotx-button__text--large'

// 自定义前缀
bem('button', undefined, 'primary', 'my-')
// 输出: 'my-button--primary'
```

#### `addBemModifier(className, modifier)`

为已有的 CSS 类名添加修饰符。

**参数：**
- `className` (string): 现有的类名
- `modifier` (string): 要添加的修饰符

**返回值：**
- `string`: 添加修饰符后的类名

**示例：**

```javascript
import { addBemModifier } from '@knotx/utils'

// 为类名添加修饰符
addBemModifier('knotx-button', 'primary')
// 输出: 'knotx-button--primary'

addBemModifier('knotx-button__text', 'large')
// 输出: 'knotx-button__text--large'
```

### ID 生成工具

#### `generateId()`

生成唯一的随机 ID 字符串。

**返回值：**
- `string`: 生成的唯一 ID

**示例：**

```javascript
import { generateId } from '@knotx/utils'

// 生成唯一 ID
const id1 = generateId()
// 输出: 'k7j2m5n8p1r3t6'

const id2 = generateId()
// 输出: 'x9z4v2b7m1k5q8'

// 每次调用都会生成不同的 ID
console.log(id1 === id2) // false
```

### 数据操作工具

#### `isInitOperation(operation)`

检查操作是否为初始化批处理操作。

**参数：**
- `operation` (DataOperation<T>): 要检查的数据操作

**返回值：**
- `boolean`: 如果是初始化操作则返回 true

**示例：**

```javascript
import { isInitOperation } from '@knotx/utils'

const initOp = { type: 'batch', operations: [], isInit: true }
const normalOp = { type: 'add', data: { id: '1' } }

isInitOperation(initOp) // true
isInitOperation(normalOp) // false
```

#### `isDraftOperation(operation)`

检查操作是否为草稿操作。

**参数：**
- `operation` (DataOperation<T>): 要检查的数据操作

**返回值：**
- `boolean`: 如果是草稿操作则返回 true

**示例：**

```javascript
import { isDraftOperation } from '@knotx/utils'

const draftOp = { type: 'draftOperation', draftId: 'draft1', operation: { type: 'add', data: { id: '1' } } }
const normalOp = { type: 'add', data: { id: '1' } }

isDraftOperation(draftOp) // true
isDraftOperation(normalOp) // false
```

#### `isEmptyBatchOperation(operation)`

检查批处理操作是否为空。

**参数：**
- `operation` (DataOperation<T>): 要检查的数据操作

**返回值：**
- `boolean`: 如果是空批处理操作则返回 true

**示例：**

```javascript
import { isEmptyBatchOperation } from '@knotx/utils'

const emptyBatch = { type: 'batch', operations: [] }
const nonEmptyBatch = { type: 'batch', operations: [{ type: 'add', data: { id: '1' } }] }

isEmptyBatchOperation(emptyBatch) // true
isEmptyBatchOperation(nonEmptyBatch) // false
```

#### `flattenOperations(operations)`

将嵌套的批处理操作展平为单级操作数组。

**参数：**
- `operations` (DataOperation<T>[]): 要展平的操作数组

**返回值：**
- `DataOperation<T>[]`: 展平后的操作数组

**示例：**

```javascript
import { flattenOperations } from '@knotx/utils'

const nestedOps = [
  { type: 'add', data: { id: '1' } },
  {
    type: 'batch',
    operations: [
      { type: 'add', data: { id: '2' } },
      { type: 'remove', id: '3' }
    ]
  }
]

const flatOps = flattenOperations(nestedOps)
// 输出: [
//   { type: 'add', data: { id: '1' } },
//   { type: 'add', data: { id: '2' } },
//   { type: 'remove', id: '3' }
// ]
```

#### `emptyOperation()`

创建一个空的批处理操作。

**返回值：**
- `DataEmptyBatchOperation<T>`: 空的批处理操作

**示例：**

```javascript
import { emptyOperation } from '@knotx/utils'

const empty = emptyOperation()
// 输出: { type: 'batch', operations: [] }
```

#### `buildDiffOperation(previousDataMap, dataMap, compare?)`

构建两个数据映射之间的差异操作。

**参数：**
- `previousDataMap` (Map<string, T>): 之前的数据映射
- `dataMap` (Map<string, T>): 当前的数据映射
- `compare` (function, 可选): 比较函数，默认为 `Object.is`

**返回值：**
- `DataBatchOperation<T>`: 包含差异操作的批处理操作

**示例：**

```javascript
import { buildDiffOperation } from '@knotx/utils'

const prevData = new Map([
  ['1', { id: '1', name: 'Alice' }],
  ['2', { id: '2', name: 'Bob' }]
])

const currentData = new Map([
  ['1', { id: '1', name: 'Alice Updated' }],
  ['3', { id: '3', name: 'Charlie' }]
])

const diffOp = buildDiffOperation(prevData, currentData)
// 输出: {
//   type: 'batch',
//   operations: [
//     { type: 'remove', id: '2' },
//     { type: 'add', data: { id: '3', name: 'Charlie' } },
//     { type: 'update', id: '1', data: { id: '1', name: 'Alice Updated' } }
//   ],
//   isInit: false
// }
```

### 符号工具

#### `getSymbol(name)`

获取或创建一个带有名称标识的符号。

**参数：**
- `name` (string): 符号名称

**返回值：**
- `symbol`: 带有名称标识的符号

**示例：**

```javascript
import { getSymbol } from '@knotx/utils'

// 获取符号
const sym1 = getSymbol('mySymbol')
const sym2 = getSymbol('mySymbol')

console.log(sym1 === sym2) // true - 相同名称返回相同符号
console.log(sym1.toString()) // 'Symbol(knotx:mySymbol)'

// 不同名称返回不同符号
const sym3 = getSymbol('anotherSymbol')
console.log(sym1 === sym3) // false
```

## 项目结构

```
packages/utils/
├── src/
│   ├── index.ts        # 主入口文件，导出所有工具函数
│   ├── bem.ts          # BEM 命名约定工具
│   ├── id.ts           # ID 生成工具
│   ├── operation.ts    # 数据操作工具
│   └── symbol.ts       # 符号工具
├── dist/               # 编译输出目录
├── package.json        # 包配置文件
├── tsconfig.json       # TypeScript 配置
├── build.config.ts     # 构建配置
└── README.md          # 中文文档
```

## 类型定义

本包提供了完整的 TypeScript 类型定义，包括：

- `DataInitBatchOperation<T>`: 初始化批处理操作类型
- `DataEmptyBatchOperation<T>`: 空批处理操作类型
- 以及所有函数的参数和返回值类型

## 依赖

- `@knotx/data`: 数据操作相关类型定义

## 许可证

MIT

## 贡献

欢迎提交 Issues 和 Pull Requests 来改进这个包。

## 更多信息

- [GitHub 仓库](https://github.com/boenfu/knotx)
- [官方网站](https://github.com/boenfu/knotx#readme)