wssf-kage-js 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -293
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -1,339 +1,131 @@
|
|
|
1
|
-
# Kage.js
|
|
1
|
+
# Kage.js (`wssf-kage-js`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
面向 **前端与 AI 业务** 的 TypeScript 函数式工具集合:柯里化、组合、高阶拦截、纯函数、惰性/记忆化、中间件、策略、Option 等 **24 类常见函数模式**,便于组合提示词流水线、鉴权与降级、数据变换等逻辑。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- **运行时零依赖**(`dependencies` 为空)
|
|
6
|
+
- 发布物仅含 `dist`(CJS + ESM + `.d.ts`),支持按需 `import`
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- 📦 **模块化设计** - 支持按需导入,减小打包体积
|
|
9
|
-
- 🧪 **完善的测试** - 100% 测试覆盖率
|
|
10
|
-
- 🔧 **零依赖** - 不依赖任何第三方库
|
|
11
|
-
- 📝 **详细的文档** - 每个函数都有清晰的注释
|
|
8
|
+
> npm 页面展示的是本 README。更完整的说明、分节示例见仓库内 [**Docusaurus 文档**](https://github.com/hezihua/Kage_js/tree/main/docs)(`pnpm run docs:dev` 本地预览)。
|
|
12
9
|
|
|
13
|
-
##
|
|
10
|
+
## 安装
|
|
14
11
|
|
|
15
12
|
```bash
|
|
16
13
|
npm install wssf-kage-js
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
或使用 yarn:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
yarn add wssf-kage-js
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
或使用 pnpm:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
14
|
+
# 或
|
|
28
15
|
pnpm add wssf-kage-js
|
|
29
16
|
```
|
|
30
17
|
|
|
31
|
-
##
|
|
18
|
+
## 快速开始
|
|
32
19
|
|
|
33
|
-
|
|
34
|
-
import { chunk, camelCase, debounce, range } from 'wssf-kage-js';
|
|
20
|
+
### 柯里化与普通工具(`curry`、`pipe`、`debounce` …)
|
|
35
21
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// => [[1, 2], [3, 4], [5]]
|
|
22
|
+
```ts
|
|
23
|
+
import { curry, pipe, debounce } from 'wssf-kage-js';
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// => 'helloWorld'
|
|
25
|
+
const add = (a: number, b: number, c: number) => a + b + c;
|
|
26
|
+
curry(add)(1)(2)(3); // => 6
|
|
43
27
|
|
|
44
|
-
//
|
|
45
|
-
const debouncedFn = debounce(() => console.log('执行'), 1000);
|
|
28
|
+
pipe<string>((s) => s.trim(), (s) => s.toUpperCase())(' hi '); // => 'HI'
|
|
46
29
|
|
|
47
|
-
|
|
48
|
-
range(5);
|
|
49
|
-
// => [0, 1, 2, 3, 4]
|
|
30
|
+
const onResize = debounce(200)(() => console.log('resize'));
|
|
50
31
|
```
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### 函数模式总览
|
|
55
|
-
|
|
56
|
-
项目已经内置 24 类常见函数模式,包括柯里化、高阶函数、组合函数、纯函数、惰性函数、记忆化函数、中间件函数、生成器函数等。
|
|
57
|
-
|
|
58
|
-
- 总览文档: [FUNCTION_TYPES.md](./FUNCTION_TYPES.md)
|
|
59
|
-
- Docusaurus 文档骨架: [docs/intro.md](./docs/intro.md)
|
|
60
|
-
- 示例入口: [examples.ts](./examples.ts)
|
|
61
|
-
|
|
62
|
-
### 语言检查 (Lang)
|
|
63
|
-
|
|
64
|
-
判断数据类型的工具函数。
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
import { isNil, isArray, isObject, isEmpty } from 'wssf-kage-js';
|
|
68
|
-
|
|
69
|
-
isNil(null); // => true
|
|
70
|
-
isArray([1, 2, 3]); // => true
|
|
71
|
-
isObject({}); // => true
|
|
72
|
-
isEmpty([]); // => true
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
**可用方法:**
|
|
76
|
-
- `isNil(value)` - 检查是否为 null 或 undefined
|
|
77
|
-
- `isArray(value)` - 检查是否为数组
|
|
78
|
-
- `isObject(value)` - 检查是否为对象
|
|
79
|
-
- `isFunction(value)` - 检查是否为函数
|
|
80
|
-
- `isString(value)` - 检查是否为字符串
|
|
81
|
-
- `isNumber(value)` - 检查是否为数字
|
|
82
|
-
- `isBoolean(value)` - 检查是否为布尔值
|
|
83
|
-
- `isEmpty(value)` - 检查是否为空
|
|
84
|
-
|
|
85
|
-
### 数组操作 (Array)
|
|
86
|
-
|
|
87
|
-
强大的数组处理工具。
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
import { chunk, uniq, flatten, shuffle } from 'wssf-kage-js';
|
|
91
|
-
|
|
92
|
-
// 分块
|
|
93
|
-
chunk([1, 2, 3, 4, 5], 2);
|
|
94
|
-
// => [[1, 2], [3, 4], [5]]
|
|
33
|
+
### 组合与 Prompt / 意图流水线(`compose.ts`)
|
|
95
34
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// => [1, 2, 3]
|
|
35
|
+
```ts
|
|
36
|
+
import { sanitizePrompt, routeIntent, withFallback } from 'wssf-kage-js';
|
|
99
37
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
// => [1, 2, 3, 4]
|
|
38
|
+
sanitizePrompt(' <b>x</b> ');
|
|
39
|
+
routeIntent({ text: '美元汇率' });
|
|
103
40
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// => [3, 1, 5, 2, 4] (随机顺序)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**可用方法:**
|
|
110
|
-
- `head(array)` - 获取第一个元素
|
|
111
|
-
- `last(array)` - 获取最后一个元素
|
|
112
|
-
- `tail(array)` - 获取除第一个元素外的所有元素
|
|
113
|
-
- `uniq(array)` - 数组去重
|
|
114
|
-
- `uniqBy(array, iteratee)` - 根据迭代函数去重
|
|
115
|
-
- `flatten(array)` - 浅层扁平化
|
|
116
|
-
- `flattenDeep(array)` - 深度扁平化
|
|
117
|
-
- `chunk(array, size)` - 分块数组
|
|
118
|
-
- `compact(array)` - 过滤假值
|
|
119
|
-
- `difference(array, values)` - 数组差集
|
|
120
|
-
- `intersection(array, ...arrays)` - 数组交集
|
|
121
|
-
- `sum(array)` - 数组求和
|
|
122
|
-
- `sumBy(array, iteratee)` - 根据迭代函数求和
|
|
123
|
-
- `shuffle(array)` - 随机打乱
|
|
124
|
-
- `sample(array)` - 随机取一个元素
|
|
125
|
-
- `sampleSize(array, n)` - 随机取 n 个元素
|
|
126
|
-
|
|
127
|
-
### 对象操作 (Object)
|
|
128
|
-
|
|
129
|
-
灵活的对象处理方法。
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
import { get, set, merge, pick, omit } from 'wssf-kage-js';
|
|
133
|
-
|
|
134
|
-
const obj = { a: { b: { c: 3 } } };
|
|
135
|
-
|
|
136
|
-
// 获取嵌套属性
|
|
137
|
-
get(obj, 'a.b.c');
|
|
138
|
-
// => 3
|
|
139
|
-
|
|
140
|
-
// 设置嵌套属性
|
|
141
|
-
set(obj, 'a.b.d', 4);
|
|
142
|
-
// => { a: { b: { c: 3, d: 4 } } }
|
|
143
|
-
|
|
144
|
-
// 合并对象
|
|
145
|
-
merge({ a: 1 }, { b: 2 });
|
|
146
|
-
// => { a: 1, b: 2 }
|
|
147
|
-
|
|
148
|
-
// 选取属性
|
|
149
|
-
pick({ a: 1, b: 2, c: 3 }, ['a', 'c']);
|
|
150
|
-
// => { a: 1, c: 3 }
|
|
151
|
-
|
|
152
|
-
// 排除属性
|
|
153
|
-
omit({ a: 1, b: 2, c: 3 }, ['b']);
|
|
154
|
-
// => { a: 1, c: 3 }
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**可用方法:**
|
|
158
|
-
- `cloneDeep(value)` - 深度克隆
|
|
159
|
-
- `get(obj, path, defaultValue)` - 获取嵌套属性
|
|
160
|
-
- `set(obj, path, value)` - 设置嵌套属性
|
|
161
|
-
- `merge(target, ...sources)` - 合并对象
|
|
162
|
-
- `pick(obj, keys)` - 选取属性
|
|
163
|
-
- `omit(obj, keys)` - 排除属性
|
|
164
|
-
- `keys(obj)` - 获取所有键
|
|
165
|
-
- `values(obj)` - 获取所有值
|
|
166
|
-
- `entries(obj)` - 获取键值对
|
|
167
|
-
- `invert(obj)` - 反转键值
|
|
168
|
-
- `mapValues(obj, iteratee)` - 映射对象值
|
|
169
|
-
|
|
170
|
-
### 字符串操作 (String)
|
|
171
|
-
|
|
172
|
-
丰富的字符串处理工具。
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
import { camelCase, snakeCase, kebabCase, truncate } from 'wssf-kage-js';
|
|
176
|
-
|
|
177
|
-
// 驼峰命名
|
|
178
|
-
camelCase('hello-world');
|
|
179
|
-
// => 'helloWorld'
|
|
180
|
-
|
|
181
|
-
// 蛇形命名
|
|
182
|
-
snakeCase('helloWorld');
|
|
183
|
-
// => 'hello_world'
|
|
184
|
-
|
|
185
|
-
// 短横线命名
|
|
186
|
-
kebabCase('helloWorld');
|
|
187
|
-
// => 'hello-world'
|
|
188
|
-
|
|
189
|
-
// 截断字符串
|
|
190
|
-
truncate('hello world', { length: 8 });
|
|
191
|
-
// => 'hello...'
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**可用方法:**
|
|
195
|
-
- `capitalize(str)` - 首字母大写
|
|
196
|
-
- `camelCase(str)` - 驼峰命名
|
|
197
|
-
- `snakeCase(str)` - 蛇形命名
|
|
198
|
-
- `kebabCase(str)` - 短横线命名
|
|
199
|
-
- `trim(str, chars)` - 去除空格
|
|
200
|
-
- `truncate(str, options)` - 截断字符串
|
|
201
|
-
- `words(str)` - 分词
|
|
202
|
-
- `repeat(str, n)` - 重复字符串
|
|
203
|
-
- `padStart(str, length, chars)` - 左侧填充
|
|
204
|
-
- `padEnd(str, length, chars)` - 右侧填充
|
|
205
|
-
|
|
206
|
-
### 函数工具 (Function)
|
|
207
|
-
|
|
208
|
-
高阶函数和函数式编程工具。
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
import { debounce, throttle, once, memoize, curry } from 'wssf-kage-js';
|
|
212
|
-
|
|
213
|
-
// 防抖
|
|
214
|
-
const debouncedFn = debounce(() => {
|
|
215
|
-
console.log('执行');
|
|
216
|
-
}, 1000);
|
|
217
|
-
|
|
218
|
-
// 节流
|
|
219
|
-
const throttledFn = throttle(() => {
|
|
220
|
-
console.log('执行');
|
|
221
|
-
}, 1000);
|
|
222
|
-
|
|
223
|
-
// 只执行一次
|
|
224
|
-
const onceFn = once(() => {
|
|
225
|
-
console.log('只执行一次');
|
|
41
|
+
const safe = withFallback('降级文案')(async () => {
|
|
42
|
+
throw new Error('fail');
|
|
226
43
|
});
|
|
227
|
-
|
|
228
|
-
// 记忆化
|
|
229
|
-
const memoizedFn = memoize((x) => x * 2);
|
|
230
|
-
|
|
231
|
-
// 柯里化
|
|
232
|
-
const add = (a, b, c) => a + b + c;
|
|
233
|
-
const curriedAdd = curry(add);
|
|
234
|
-
curriedAdd(1)(2)(3); // => 6
|
|
44
|
+
await safe();
|
|
235
45
|
```
|
|
236
46
|
|
|
237
|
-
|
|
238
|
-
- `debounce(func, wait, options)` - 防抖
|
|
239
|
-
- `throttle(func, wait, options)` - 节流
|
|
240
|
-
- `once(func)` - 只执行一次
|
|
241
|
-
- `delay(func, wait, ...args)` - 延迟执行
|
|
242
|
-
- `memoize(func, resolver)` - 记忆化
|
|
243
|
-
- `curry(func, arity)` - 柯里化
|
|
244
|
-
- `compose(...funcs)` - 函数组合
|
|
245
|
-
- `pipe(...funcs)` - 管道函数
|
|
246
|
-
|
|
247
|
-
### 数学运算 (Math)
|
|
248
|
-
|
|
249
|
-
常用的数学计算工具。
|
|
47
|
+
### 纯函数与闭包
|
|
250
48
|
|
|
251
|
-
```
|
|
252
|
-
import {
|
|
49
|
+
```ts
|
|
50
|
+
import { normalizeText, sumNumbers, createCounter } from 'wssf-kage-js';
|
|
253
51
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
// => [0, 1, 2, 3, 4]
|
|
52
|
+
normalizeText(' Hello ');
|
|
53
|
+
sumNumbers([1, 2, 3]);
|
|
257
54
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
range(0, 10, 2);
|
|
262
|
-
// => [0, 2, 4, 6, 8]
|
|
263
|
-
|
|
264
|
-
// 随机数
|
|
265
|
-
random(1, 10);
|
|
266
|
-
// => 7 (随机)
|
|
267
|
-
|
|
268
|
-
// 限制范围
|
|
269
|
-
clamp(15, 1, 10);
|
|
270
|
-
// => 10
|
|
271
|
-
|
|
272
|
-
// 求平均值
|
|
273
|
-
mean([1, 2, 3, 4, 5]);
|
|
274
|
-
// => 3
|
|
55
|
+
const c = createCounter(0);
|
|
56
|
+
c.increment();
|
|
275
57
|
```
|
|
276
58
|
|
|
277
|
-
|
|
278
|
-
- `range(start, end, step)` - 生成数字范围
|
|
279
|
-
- `random(min, max, floating)` - 生成随机数
|
|
280
|
-
- `clamp(number, min, max)` - 限制数字范围
|
|
281
|
-
- `ceil(number, precision)` - 向上取整
|
|
282
|
-
- `floor(number, precision)` - 向下取整
|
|
283
|
-
- `round(number, precision)` - 四舍五入
|
|
284
|
-
- `mean(array)` - 求平均值
|
|
285
|
-
- `max(array)` - 求最大值
|
|
286
|
-
- `min(array)` - 求最小值
|
|
287
|
-
- `maxBy(array, iteratee)` - 根据迭代函数求最大值
|
|
288
|
-
- `minBy(array, iteratee)` - 根据迭代函数求最小值
|
|
289
|
-
|
|
290
|
-
## 🧪 测试
|
|
59
|
+
### 异步与生成器
|
|
291
60
|
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
npm test
|
|
61
|
+
```ts
|
|
62
|
+
import { asyncMap, retryAsync, createRange, streamChunks } from 'wssf-kage-js';
|
|
295
63
|
|
|
296
|
-
|
|
297
|
-
|
|
64
|
+
await asyncMap([1, 2], async (n) => n * 2);
|
|
65
|
+
await retryAsync(async () => 'ok', 2);
|
|
298
66
|
|
|
299
|
-
|
|
300
|
-
npm run test:coverage
|
|
301
|
-
```
|
|
67
|
+
[...createRange(1, 3)];
|
|
302
68
|
|
|
303
|
-
|
|
69
|
+
for await (const x of streamChunks(['a', 'b'], 0)) {
|
|
70
|
+
console.log(x);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
304
73
|
|
|
305
|
-
|
|
74
|
+
## 导出结构(与源码目录对应)
|
|
75
|
+
|
|
76
|
+
| 模块 | 代表能力 / 符号 |
|
|
77
|
+
|------|------------------|
|
|
78
|
+
| `currying` | `curry`、`compose`、`pipe`、`get`/`set`、`map`/`filter`/`reduce`、`debounce`、`throttle`、`logger`、`request`、`validate` … |
|
|
79
|
+
| `compose` | `composePipe`、`sanitizePrompt`、`safetyGate`、`routeIntent`、`tokenManager`、`buildPrompt`、`dataPipeline`、`processSearchList` … |
|
|
80
|
+
| `higherOrder` | `withPermission`、`withPerformance`、`withTokenAudit`、`withFallback`、`withSanitizer`、`withLock`、`withAuditTrail`、`withUIFormat` |
|
|
81
|
+
| `pureFunction` | `sumNumbers`、`normalizeText`、`calculateWeightedScore` |
|
|
82
|
+
| `closureFunction` | `createCounter`、`createAccumulator` |
|
|
83
|
+
| `partialFunction` | `partial`、`partialRight` |
|
|
84
|
+
| `decoratorFunction` | `withLogging`、`withRetry` |
|
|
85
|
+
| `middlewareFunction` | `runMiddleware`、`createLogMiddleware` |
|
|
86
|
+
| `strategyFunction` | `createStrategyRunner`、`financeStrategy`、`codingStrategy`、`defaultStrategy` |
|
|
87
|
+
| `guardFunction` | `assertDefined`、`assertNonEmptyArray`、`isRecord` |
|
|
88
|
+
| `predicateFunction` | `isNonEmptyString`、`isPositiveNumber`、`andPredicate`、`orPredicate` |
|
|
89
|
+
| `transformerFunction` | `toUserViewModel`、`transformCollection` |
|
|
90
|
+
| `reducerFunction` | `counterReducer`、`reduceItems` |
|
|
91
|
+
| `recursiveFunction` / `tailRecursiveFunction` | `factorialRecursive`、`flattenTree`、`factorialTailRecursive`、`sumTailRecursive` |
|
|
92
|
+
| `lazyFunction` | `deferValue`、`createOnceResolver`、`mapLazyValue` |
|
|
93
|
+
| `memoizedFunction` | `memoizeUnary`、`clearMemoizedCache` |
|
|
94
|
+
| `callbackFunction` | `mapWithCallback`、`forEachWithCallback`、`createDelayedCallback` |
|
|
95
|
+
| `asyncFunction` | `delay`、`asyncMap`、`retryAsync` |
|
|
96
|
+
| `generatorFunction` / `asyncGeneratorFunction` | `createRange`、`iterateWords`、`streamChunks`、`collectAsyncGenerator` |
|
|
97
|
+
| `factoryFunction` | `createFormatter`、`createThresholdChecker` |
|
|
98
|
+
| `pointFreeFunction` | `mapValues`、`filterValues`、`joinWith`、`pointFreeUserNames` |
|
|
99
|
+
| `monadFunction` | `some`、`none`、`mapOption`、`flatMapOption`、`getOptionOrElse` |
|
|
100
|
+
|
|
101
|
+
完整分节说明与「每函数一例」见仓库 [**`docs/function-types/`**](https://github.com/hezihua/Kage_js/tree/main/docs/function-types)。
|
|
102
|
+
|
|
103
|
+
## 本地开发与文档
|
|
306
104
|
|
|
307
105
|
```bash
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
#
|
|
312
|
-
|
|
106
|
+
pnpm install
|
|
107
|
+
pnpm run build # 产出 dist/
|
|
108
|
+
pnpm test # 测试(若已配置)
|
|
109
|
+
pnpm run docs:dev # Docusaurus 文档站
|
|
110
|
+
pnpm run docs:site:build
|
|
313
111
|
```
|
|
314
112
|
|
|
315
|
-
|
|
113
|
+
TypeDoc 默认输出目录为 `typedoc-html/`(见 `typedoc.json`),与文档站 Markdown 源码分离。
|
|
316
114
|
|
|
317
|
-
|
|
115
|
+
## 许可证
|
|
318
116
|
|
|
319
|
-
|
|
117
|
+
MIT
|
|
320
118
|
|
|
321
|
-
|
|
322
|
-
npm run build
|
|
323
|
-
```
|
|
119
|
+
## 更新日志
|
|
324
120
|
|
|
325
|
-
|
|
121
|
+
### 1.0.2
|
|
326
122
|
|
|
327
|
-
|
|
123
|
+
- 修正 npm README:与当前 `src` 导出一致,移除不存在的 lodash 式 API 描述。
|
|
328
124
|
|
|
329
|
-
|
|
125
|
+
### 1.0.1
|
|
330
126
|
|
|
331
|
-
|
|
127
|
+
- 发版指向 npm 官方 `registry`;安装仍可使用国内镜像(见仓库 `.npmrc` 说明)。
|
|
332
128
|
|
|
333
|
-
|
|
129
|
+
### 1.0.0
|
|
334
130
|
|
|
335
|
-
|
|
336
|
-
- 🎉 首次发布
|
|
337
|
-
- ✨ 支持数组、对象、字符串、函数和数学运算工具
|
|
338
|
-
- 📝 完善的 TypeScript 类型定义
|
|
339
|
-
- 🧪 完整的测试覆盖
|
|
131
|
+
- 首次公开发布。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wssf-kage-js",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "TypeScript 函数式工具:柯里化、组合、高阶拦截、纯函数、中间件等 24 类模式,面向前端与 AI 流水线",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
},
|
|
15
15
|
"homepage": "https://github.com/hezihua/Kage_js#readme",
|
|
16
16
|
"keywords": [
|
|
17
|
-
"utility",
|
|
18
|
-
"lodash",
|
|
19
17
|
"functional",
|
|
20
|
-
"array",
|
|
21
|
-
"object",
|
|
22
|
-
"string",
|
|
23
18
|
"typescript",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
19
|
+
"currying",
|
|
20
|
+
"compose",
|
|
21
|
+
"higher-order",
|
|
22
|
+
"middleware",
|
|
23
|
+
"prompt",
|
|
24
|
+
"ai",
|
|
25
|
+
"utilities",
|
|
26
|
+
"fp"
|
|
27
27
|
],
|
|
28
28
|
"author": "hezihua <2283462371@qq.com>",
|
|
29
29
|
"license": "MIT",
|