foreslash 0.2.0 → 0.2.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/CHANGELOG.md +97 -0
- package/README.EN.md +131 -0
- package/README.md +83 -39
- package/lib/index.cmn.cjs +155 -4
- package/lib/index.d.ts +107 -1
- package/lib/index.mjs +151 -5
- package/lib/index.umd.js +155 -4
- package/package.json +6 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
## Version 0.2.2 - 2025-03-18
|
|
4
|
+
|
|
5
|
+
Unstable version
|
|
6
|
+
|
|
7
|
+
- Feat 🥥 Functions added: `throttle` `debounce` `remove` and `clamp`
|
|
8
|
+
- Other fixes and improvements
|
|
9
|
+
|
|
10
|
+
不稳定版本
|
|
11
|
+
|
|
12
|
+
- 功能 🥥 添加函数: `throttle` `debounce` `remove` 和 `clamp`
|
|
13
|
+
- 其他修复与优化
|
|
14
|
+
|
|
15
|
+
## Version 0.2.1 - 2025-02-23
|
|
16
|
+
|
|
17
|
+
Unstable version
|
|
18
|
+
|
|
19
|
+
- Feat 🥥 Functions added: `memo`
|
|
20
|
+
- Feat 🥥 Function change: `range` now support single parameter invocation, *compatible with Radash*
|
|
21
|
+
- Fix 🥕 Bug fixed: `deepClone` now processes `DataView.buffer` properly
|
|
22
|
+
- Fix 🥕 Bug fixed: Correct type definition filepath
|
|
23
|
+
- Other fixes and improvements
|
|
24
|
+
|
|
25
|
+
不稳定版本
|
|
26
|
+
|
|
27
|
+
- 功能 🥥 添加函数: `memo`
|
|
28
|
+
- 功能 🥥 变更函数: `range` 现在支持单个参数的调用, *与 Radash 兼容*
|
|
29
|
+
- 修复 🥕 缺陷修复: `deepClone` 现在能正确处理 `DataView.buffer`
|
|
30
|
+
- 修复 🥕 缺陷修复: 修复了类型定义文件路径
|
|
31
|
+
- 其他修复与优化
|
|
32
|
+
|
|
33
|
+
## Version 0.2.0 - 2025-02-16
|
|
34
|
+
|
|
35
|
+
Unstable version
|
|
36
|
+
|
|
37
|
+
- Change 🥟 Functions changed: `caseCamel` `casePascal` `caseKebab` `caseSnake` now deprecated, will be removed in the future, use `camelCase` `pascalCase` `kebabCase` `snakeCase` instead
|
|
38
|
+
- Feat 🥥 Functions added: `isTypedArray` `range` `titleCase` `tryit` `withResolvers` and so forth
|
|
39
|
+
- Feat 🥥 Function change: `isEmpty` now validates Date object
|
|
40
|
+
- Feat 🥥 Function change: `fastClone` now clones FormData object
|
|
41
|
+
- Wip 🍉 Function wip: `deepClone` still on progress
|
|
42
|
+
- Other fixes and improvements
|
|
43
|
+
|
|
44
|
+
不稳定版本
|
|
45
|
+
|
|
46
|
+
- 变更 🥟 变更函数: `caseCamel` `casePascal` `caseKebab` `caseSnake` 弃用,将来会移除,请改用 `camelCase` `pascalCase` `kebabCase` `snakeCase`
|
|
47
|
+
- 功能 🥥 添加函数: `isTypedArray` `range` `titleCase` `tryit` `withResolvers` 等
|
|
48
|
+
- 功能 🥥 变更函数: `isEmpty` 现在会校验 Date 对象
|
|
49
|
+
- 功能 🥥 变更函数: `fastClone` 现在会复制 FormData 对象
|
|
50
|
+
- 开发中 🍉 函数开发中: `deepClone` 尚在开发中
|
|
51
|
+
- 其他修复与优化
|
|
52
|
+
|
|
53
|
+
## Version 0.1.2 - 2025-01-09
|
|
54
|
+
|
|
55
|
+
Unstable version
|
|
56
|
+
|
|
57
|
+
- Feat 🥥 Functions added: `caseConvert` `uuidV4` `ulid` and so forth
|
|
58
|
+
- Feat 🥥 Misc functions added: `acceptableFileName` `acceptableFileType` `getAcceptableExtByMIME` and `getAcceptableMIMEByExt`
|
|
59
|
+
- Fix 🥕 Bug fixed: Unexpected export `_fastClone`
|
|
60
|
+
- Other fixes and improvements
|
|
61
|
+
|
|
62
|
+
不稳定版本
|
|
63
|
+
|
|
64
|
+
- 功能 🥥 添加函数: `caseConvert` `uuidV4` `ulid` 等
|
|
65
|
+
- 功能 🥥 添加杂项函数: `acceptableFileName` `acceptableFileType` `getAcceptableExtByMIME` 和 `getAcceptableMIMEByExt`
|
|
66
|
+
- 修复 🥕 缺陷修复: 不应导出 `_fastClone`
|
|
67
|
+
- 其他修复与优化
|
|
68
|
+
|
|
69
|
+
## Version 0.1.1 - 2024-11-11
|
|
70
|
+
|
|
71
|
+
Unstable version
|
|
72
|
+
|
|
73
|
+
- Feat 🥥 Functions added: `isEmpty` `shuffle` `isPrimitive` and so forth
|
|
74
|
+
- Fix 🥕 Bug fixed: `isNil(document.all)` expected to be `false`
|
|
75
|
+
- Other fixes and improvements
|
|
76
|
+
|
|
77
|
+
不稳定版本
|
|
78
|
+
|
|
79
|
+
- 功能 🥥 添加函数: `isEmpty` `shuffle` `isPrimitive` 等
|
|
80
|
+
- 修复 🥕 缺陷修复: `isNil(document.all)` 应为 `false`
|
|
81
|
+
- 其他修复与优化
|
|
82
|
+
|
|
83
|
+
## Version 0.1.0 - 2024-09-28
|
|
84
|
+
|
|
85
|
+
Unstable version
|
|
86
|
+
|
|
87
|
+
- Feat 🥥 Functions added: `fastClone` `compose` `getTag` and so forth
|
|
88
|
+
- Feat 🥥 Function change: `curry` now supports optional arguments
|
|
89
|
+
- Fix 🥕 Bug fixed: Type hint for `passWith` now corrected
|
|
90
|
+
- Other fixes and improvements
|
|
91
|
+
|
|
92
|
+
不稳定版本
|
|
93
|
+
|
|
94
|
+
- 功能 🥥 添加函数: `fastClone` `compose` `getTag` 等
|
|
95
|
+
- 功能 🥥 变更函数: `curry` 支持可选参数
|
|
96
|
+
- 修复 🥕 缺陷修复: 修复了 `passWith` 的类型提示
|
|
97
|
+
- 其他修复与优化
|
package/README.EN.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Foreslash
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<p align="center">
|
|
5
|
+
<img src="https://img.shields.io/github/languages/top/Moushudyx/foreslash" alt="GitHub top lang" />
|
|
6
|
+
<img src="https://img.shields.io/badge/license-Mulan_PSL_v2-blue" alt="GitHub license" />
|
|
7
|
+
<img src="https://img.shields.io/npm/v/foreslash" alt="NPM Version" />
|
|
8
|
+
<img src="https://img.shields.io/npm/dm/foreslash" alt="NPM Downloads" />
|
|
9
|
+
<img src="https://img.shields.io/bundlejs/size/foreslash?label=gzipped" alt="NPM package gzipped size" />
|
|
10
|
+
</p>
|
|
11
|
+
<p align="center">
|
|
12
|
+
Foreslash is a Javascript utilities lib which contains plenty of practical functions.
|
|
13
|
+
</p>
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://moushudyx.github.io/foreslash/en">Documentation</a>
|
|
16
|
+
</p>
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="./README.md">中文</a>
|
|
19
|
+
|
|
|
20
|
+
<span>English</span>
|
|
21
|
+
</p>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
## Why Foreslash
|
|
25
|
+
|
|
26
|
+
### Type definitions
|
|
27
|
+
|
|
28
|
+
Foreslash comes with comprehensive type definitions out of the box, eliminating the need to install `@types/XXX`.
|
|
29
|
+
|
|
30
|
+
- Foreslash is developed using [typescript](https://github.com/microsoft/TypeScript), and we uses [jest](https://github.com/facebook/jest) and [ts-jest](https://github.com/kulshekhar/ts-jest) for unit testing.
|
|
31
|
+
|
|
32
|
+
### Minimal Side Effects
|
|
33
|
+
|
|
34
|
+
Unless explicitly stated, methods in Foreslash are designed with **minimal side effects**.
|
|
35
|
+
|
|
36
|
+
- Methods from Foreslash do not modify mutate input data, they return a new data instead.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import { shuffle } from 'foreslash'
|
|
40
|
+
|
|
41
|
+
const arr = [1, 2, 3, 4, 5, 6, 7, 8]
|
|
42
|
+
const shuffled = shuffle(arr) // Returns a new array [3, 2, 6, 5, 8, 1, 7, 4] while `arr` remains unchanged
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Functional Programming
|
|
46
|
+
|
|
47
|
+
Foreslash offers functional programming utilities methods like `curry`、`pipe`.
|
|
48
|
+
|
|
49
|
+
- For performance reasons, methods are **not curried** unless explicitly stated.
|
|
50
|
+
- The curry method `curry` and the placeholder `_` in Foreslash are compatible with [Ramda](https://github.com/ramda/ramda).
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
import { curry, _ } from 'foreslash'
|
|
54
|
+
|
|
55
|
+
// const regTest = (regex) => (str) => regex.test(str) // The order of arguments is strictly defined and less flexible
|
|
56
|
+
const regTest = curry((str, regex) => regex.test(str)) // Currying a function to make it more flexible and reusable
|
|
57
|
+
|
|
58
|
+
const testString = regTest('123')
|
|
59
|
+
testString(/^\d+$/) // true
|
|
60
|
+
testString(/^[a-z]+$/) // false
|
|
61
|
+
|
|
62
|
+
const isDigits = regTest(_, /^\d+$/) // Using a placeholder to skip certain arguments
|
|
63
|
+
isDigits('123') // true
|
|
64
|
+
isDigits('abc') // false
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Install & Usage
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install foreslash # Install with npm
|
|
71
|
+
yarn add foreslash # Install with yarn
|
|
72
|
+
pnpm install foreslash # Install with pnpm
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Foreslash supports ESM/CJS/UMD, and ESM is recommended.
|
|
76
|
+
|
|
77
|
+
Visit [document](https://moushudyx.github.io/foreslash) for more API.
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
// curry & randomString
|
|
81
|
+
import { _, curry, randomString } from 'foreslash'
|
|
82
|
+
|
|
83
|
+
randomString(3) // 'bcD' or 'T30' or '7c5' or ...
|
|
84
|
+
|
|
85
|
+
const curriedRanStr = curry(randomString)
|
|
86
|
+
|
|
87
|
+
const randomABCD = curriedRanStr(_, 'ABCD')
|
|
88
|
+
randomABCD(3) // 'BDC' or 'ACD' or 'DBB' or ...
|
|
89
|
+
|
|
90
|
+
const random1234 = curriedRanStr(_, '1234')
|
|
91
|
+
random1234(3) // '431' or '213' or '241' or ...
|
|
92
|
+
|
|
93
|
+
// fastClone
|
|
94
|
+
import { fastClone } from 'foreslash'
|
|
95
|
+
|
|
96
|
+
const obj = { a: { b: { c: {} } }, map: new Map() }
|
|
97
|
+
obj.a.b.c.d = obj
|
|
98
|
+
obj.map.set(obj, 'val')
|
|
99
|
+
|
|
100
|
+
const clone = fastClone(obj)
|
|
101
|
+
clone === obj // false
|
|
102
|
+
// clone Deep
|
|
103
|
+
clone.a.b.c === obj.a.b.c // false
|
|
104
|
+
clone.a.b.c.d === clone // true
|
|
105
|
+
// clone Map
|
|
106
|
+
clone.map === obj.map // false
|
|
107
|
+
clone.map.get(clone) === 'val' // true
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Compatibility
|
|
111
|
+
|
|
112
|
+
Foreslash compatible with any Javascript runtime that runs ES6 code, including Node.js and web browser.
|
|
113
|
+
|
|
114
|
+
- Internet Explorer is not supported, [core-js](https://github.com/zloirock/core-js) and transformation into ES5(ES2009) via [babel](https://babeljs.io/) might be needed.
|
|
115
|
+
|
|
116
|
+
## Credits
|
|
117
|
+
|
|
118
|
+
Foreslash based on the following open source projects.
|
|
119
|
+
|
|
120
|
+
- [jest](https://github.com/facebook/jest)
|
|
121
|
+
- [rollup](https://github.com/rollup/rollup)
|
|
122
|
+
- [ts-jest](https://github.com/kulshekhar/ts-jest)
|
|
123
|
+
- [ts-toolbelt](https://github.com/millsp/ts-toolbelt)
|
|
124
|
+
- [typescript](https://github.com/microsoft/TypeScript)
|
|
125
|
+
- [vitepress](https://github.com/vuejs/vitepress)
|
|
126
|
+
- [yarn](https://github.com/yarnpkg/yarn)
|
|
127
|
+
|
|
128
|
+
Some of the methods are inspired by the following open source projects.
|
|
129
|
+
|
|
130
|
+
- [radash](https://github.com/sodiray/radash)
|
|
131
|
+
- [ramda](https://github.com/ramda/ramda)
|
package/README.md
CHANGED
|
@@ -1,36 +1,77 @@
|
|
|
1
1
|
# Foreslash
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
<div align="center">
|
|
4
|
+
<p align="center">
|
|
5
|
+
<img src="https://img.shields.io/github/languages/top/Moushudyx/foreslash" alt="GitHub top lang" />
|
|
6
|
+
<a href="https://github.com/moushudyx/foreslash/blob/master/LICENSE">
|
|
7
|
+
<img src="https://img.shields.io/badge/license-Mulan_PSL_v2-blue" alt="GitHub license" />
|
|
8
|
+
</a>
|
|
9
|
+
<img src="https://img.shields.io/npm/v/foreslash" alt="NPM Version" />
|
|
10
|
+
<img src="https://img.shields.io/npm/dm/foreslash" alt="NPM Downloads" />
|
|
11
|
+
<img src="https://img.shields.io/bundlejs/size/foreslash?label=gzipped" alt="NPM package gzipped size" />
|
|
12
|
+
</p>
|
|
13
|
+
<p align="center">
|
|
14
|
+
Foreslash 是一个 Javascript 工具库,包含大量实用函数。
|
|
15
|
+
</p>
|
|
16
|
+
<p align="center">
|
|
17
|
+
Foreslash is a Javascript utilities lib which contains plenty of practical functions.
|
|
18
|
+
</p>
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="https://moushudyx.github.io/foreslash">文档</a>
|
|
21
|
+
|
|
|
22
|
+
<a href="https://moushudyx.github.io/foreslash/en">Documentation</a>
|
|
23
|
+
</p>
|
|
24
|
+
<p align="center">
|
|
25
|
+
<span>中文</span>
|
|
26
|
+
|
|
|
27
|
+
<a href="./README.EN.md">English</a>
|
|
28
|
+
</p>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
## 为何选择 Foreslash
|
|
32
|
+
|
|
33
|
+
### 完整类型提示
|
|
34
|
+
|
|
35
|
+
Foreslash 自带完整的类型提示,无需安装 `@types/XXX`。
|
|
36
|
+
|
|
37
|
+
- Foreslash 使用 [typescript](https://github.com/microsoft/TypeScript) 开发,并使用 [jest](https://github.com/facebook/jest) 和 [ts-jest](https://github.com/kulshekhar/ts-jest) 编写单元测试。
|
|
38
|
+
|
|
39
|
+
### 低副作用
|
|
40
|
+
|
|
41
|
+
若无特殊说明,Foreslash 的任何方法都**几乎没有副作用**
|
|
42
|
+
|
|
43
|
+
- Foreslash 的方法不会修改传入的原数据,返回值将是一个新的数据。
|
|
8
44
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Foreslash is a Javascript utilities lib which contains plenty of practical functions.
|
|
12
|
-
|
|
13
|
-
[文档](https://moushudyx.github.io/foreslash) | [Documentation](https://moushudyx.github.io/foreslash/en)
|
|
14
|
-
|
|
15
|
-
## 设计理念 Design Concept
|
|
45
|
+
```js
|
|
46
|
+
import { shuffle } from 'foreslash'
|
|
16
47
|
|
|
17
|
-
|
|
48
|
+
const arr = [1, 2, 3, 4, 5, 6, 7, 8]
|
|
49
|
+
const shuffled = shuffle(arr) // 返回新的数组 [3, 2, 6, 5, 8, 1, 7, 4] 同时 arr 并没有受到影响
|
|
50
|
+
```
|
|
18
51
|
|
|
19
|
-
|
|
52
|
+
### 函数式编程
|
|
20
53
|
|
|
21
|
-
|
|
54
|
+
Foreslash 提供了诸如 `curry`、`pipe` 等函数式编程的方法。
|
|
22
55
|
|
|
23
|
-
|
|
56
|
+
- 出于性能优化的考量,若无特殊说明,此库的任何方法都**不是柯里化**的。
|
|
57
|
+
- Foreslash 的柯里化方法 `curry` 和柯里化占位符 `_` 与 [ramda](https://github.com/ramda/ramda) 兼容。
|
|
24
58
|
|
|
25
|
-
|
|
59
|
+
```js
|
|
60
|
+
import { curry, _ } from 'foreslash'
|
|
26
61
|
|
|
27
|
-
|
|
62
|
+
// const regTest = (regex) => (str) => regex.test(str) // 传统方法,传入参数的顺序有强制规定不够灵活
|
|
63
|
+
const regTest = curry((str, regex) => regex.test(str)) // 这里柯里化了一个函数使其能更灵活地复用
|
|
28
64
|
|
|
29
|
-
|
|
65
|
+
const testString = regTest('123')
|
|
66
|
+
testString(/^\d+$/) // true
|
|
67
|
+
testString(/^[a-z]+$/) // false
|
|
30
68
|
|
|
31
|
-
|
|
69
|
+
const isDigits = regTest(_, /^\d+$/) // 使用占位符来跳过填充某些参数,传统方法做不到这点
|
|
70
|
+
isDigits('123') // true
|
|
71
|
+
isDigits('abc') // false
|
|
72
|
+
```
|
|
32
73
|
|
|
33
|
-
## 安装与使用
|
|
74
|
+
## 安装与使用
|
|
34
75
|
|
|
35
76
|
```bash
|
|
36
77
|
npm install foreslash # 使用 npm 安装
|
|
@@ -38,52 +79,50 @@ yarn add foreslash # 使用 yarn 安装
|
|
|
38
79
|
pnpm install foreslash # 使用 pnpm 安装
|
|
39
80
|
```
|
|
40
81
|
|
|
82
|
+
Foreslash 支持 ESM、CJS、UMD 三种引入方式,推荐使用 ESM。
|
|
83
|
+
|
|
84
|
+
更多 API 请参考[文档](https://moushudyx.github.io/foreslash)。
|
|
85
|
+
|
|
41
86
|
```js
|
|
42
87
|
// curry & randomString
|
|
43
88
|
import { _, curry, randomString } from 'foreslash'
|
|
44
89
|
|
|
45
|
-
randomString(3) // 'bcD'
|
|
90
|
+
randomString(3) // 'bcD' 或 'T30' 或 '7c5' 或 ...
|
|
46
91
|
|
|
47
92
|
const curriedRanStr = curry(randomString)
|
|
48
93
|
|
|
49
94
|
const randomABCD = curriedRanStr(_, 'ABCD')
|
|
50
|
-
randomABCD(3) // 'BDC'
|
|
95
|
+
randomABCD(3) // 'BDC' 或 'ACD' 或 'DBB' 或 ...
|
|
51
96
|
|
|
52
97
|
const random1234 = curriedRanStr(_, '1234')
|
|
53
|
-
random1234(3) // '431'
|
|
98
|
+
random1234(3) // '431' 或 '213' 或 '241' 或 ...
|
|
54
99
|
|
|
55
100
|
// fastClone
|
|
56
101
|
import { fastClone } from 'foreslash'
|
|
57
102
|
|
|
58
103
|
const obj = { a: { b: { c: {} } }, map: new Map() }
|
|
59
|
-
obj.a.b.c.d = obj
|
|
60
|
-
obj.map.set(obj, 'val')
|
|
104
|
+
obj.a.b.c.d = obj // 常见的循环引用
|
|
105
|
+
obj.map.set(obj, 'val') // Map 键上的循环引用
|
|
61
106
|
|
|
62
107
|
const clone = fastClone(obj)
|
|
63
108
|
clone === obj // false
|
|
64
|
-
//
|
|
109
|
+
// 处理深层级对象
|
|
65
110
|
clone.a.b.c === obj.a.b.c // false
|
|
66
111
|
clone.a.b.c.d === clone // true
|
|
67
|
-
//
|
|
112
|
+
// 处理 Map
|
|
68
113
|
clone.map === obj.map // false
|
|
69
114
|
clone.map.get(clone) === 'val' // true
|
|
70
115
|
```
|
|
71
116
|
|
|
72
|
-
## 兼容性
|
|
73
|
-
|
|
74
|
-
此库兼容任何能正确运行 ES6 代码的 Javascript 环境,包括 node.js 和浏览器
|
|
75
|
-
|
|
76
|
-
- 不支持 Internet Explorer,但是使用 [core-js](https://github.com/zloirock/core-js) 处理并由 [babel](https://babeljs.io/) 转译为 ES5(ES2009) 后可以使用
|
|
117
|
+
## 兼容性
|
|
77
118
|
|
|
78
|
-
|
|
119
|
+
Foreslash 兼容任何能正确运行 ES6 代码的 Javascript 环境,包括 Node.js 和浏览器。
|
|
79
120
|
|
|
80
|
-
|
|
121
|
+
- 不支持 Internet Explorer,但是使用 [core-js](https://github.com/zloirock/core-js) 处理并由 [babel](https://babeljs.io/) 转译为 ES5(ES2009) 后可以使用。
|
|
81
122
|
|
|
82
|
-
|
|
123
|
+
## 开源软件
|
|
83
124
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
## 开源软件 Credits
|
|
125
|
+
Foreslash 的诞生离不开这些开源项目:
|
|
87
126
|
|
|
88
127
|
- [jest](https://github.com/facebook/jest)
|
|
89
128
|
- [rollup](https://github.com/rollup/rollup)
|
|
@@ -92,3 +131,8 @@ clone.map.get(clone) === 'val' // true
|
|
|
92
131
|
- [typescript](https://github.com/microsoft/TypeScript)
|
|
93
132
|
- [vitepress](https://github.com/vuejs/vitepress)
|
|
94
133
|
- [yarn](https://github.com/yarnpkg/yarn)
|
|
134
|
+
|
|
135
|
+
部分方法灵感源于以下开源项目:
|
|
136
|
+
|
|
137
|
+
- [radash](https://github.com/sodiray/radash)
|
|
138
|
+
- [ramda](https://github.com/ramda/ramda)
|
package/lib/index.cmn.cjs
CHANGED
|
@@ -12,6 +12,12 @@ See the Mulan PSL v2 for more details.
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
14
|
function range(start, end, stepOrOptions) {
|
|
15
|
+
if (!isFinite(start))
|
|
16
|
+
throw new Error('start must be finite');
|
|
17
|
+
if (end == null)
|
|
18
|
+
return range(0, start);
|
|
19
|
+
if (!isFinite(end))
|
|
20
|
+
throw new Error('end must be finite');
|
|
15
21
|
let step = 1;
|
|
16
22
|
let getter = null;
|
|
17
23
|
if (typeof stepOrOptions === 'number') {
|
|
@@ -30,8 +36,6 @@ function range(start, end, stepOrOptions) {
|
|
|
30
36
|
throw new Error('step must be finite');
|
|
31
37
|
if (step === 0)
|
|
32
38
|
throw new Error('step must not be 0');
|
|
33
|
-
if (!isFinite(start) || !isFinite(end))
|
|
34
|
-
throw new Error('start and end must be finite');
|
|
35
39
|
if ((start > end && step > 0) || (start < end && step < 0))
|
|
36
40
|
step = -step;
|
|
37
41
|
const res = [];
|
|
@@ -43,6 +47,26 @@ function range(start, end, stepOrOptions) {
|
|
|
43
47
|
return res;
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
function remove(arr, ...item) {
|
|
51
|
+
const removeSet = new Set();
|
|
52
|
+
const judgerList = [];
|
|
53
|
+
for (let i = 0; i < item.length; i++) {
|
|
54
|
+
const cond = item[i];
|
|
55
|
+
if (typeof cond === 'function')
|
|
56
|
+
judgerList.push(cond);
|
|
57
|
+
else
|
|
58
|
+
removeSet.add(cond);
|
|
59
|
+
}
|
|
60
|
+
const res = [];
|
|
61
|
+
for (let i = 0; i < arr.length; i++) {
|
|
62
|
+
const el = arr[i];
|
|
63
|
+
if (removeSet.has(el) || judgerList.some((judger) => judger(el)))
|
|
64
|
+
continue;
|
|
65
|
+
res.push(el);
|
|
66
|
+
}
|
|
67
|
+
return res;
|
|
68
|
+
}
|
|
69
|
+
|
|
46
70
|
function sleep(time = 1000) {
|
|
47
71
|
return new Promise((res) => {
|
|
48
72
|
setTimeout(res, time);
|
|
@@ -281,6 +305,23 @@ function withResolvers(PromiseLike = Promise) {
|
|
|
281
305
|
return { promise, resolve, reject };
|
|
282
306
|
}
|
|
283
307
|
|
|
308
|
+
function clamp(num, min, max, options) {
|
|
309
|
+
var _a, _b;
|
|
310
|
+
if (isNaN(min))
|
|
311
|
+
throw new Error('Invalid min parameter');
|
|
312
|
+
if (isNaN(max))
|
|
313
|
+
throw new Error('Invalid max parameter');
|
|
314
|
+
if (max < min) {
|
|
315
|
+
[min, max] = [max, min];
|
|
316
|
+
}
|
|
317
|
+
const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
|
|
318
|
+
const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
|
|
319
|
+
const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
|
|
320
|
+
if (isNaN(num))
|
|
321
|
+
return defaultMin;
|
|
322
|
+
return num < min ? defaultMin : num > max ? defaultMax : num;
|
|
323
|
+
}
|
|
324
|
+
|
|
284
325
|
const mimeMap = {
|
|
285
326
|
application: {
|
|
286
327
|
acrobat: ['pdf'],
|
|
@@ -1279,6 +1320,49 @@ function _curryMore(fn) {
|
|
|
1279
1320
|
}
|
|
1280
1321
|
}
|
|
1281
1322
|
|
|
1323
|
+
function _throttle(fn, delay, options) {
|
|
1324
|
+
var _a, _b;
|
|
1325
|
+
const trailing = (_a = options === null || options === void 0 ? void 0 : options.trailing) !== null && _a !== void 0 ? _a : false;
|
|
1326
|
+
const leading = (_b = options === null || options === void 0 ? void 0 : options.leading) !== null && _b !== void 0 ? _b : true;
|
|
1327
|
+
let timer = null;
|
|
1328
|
+
let lastTime = 0;
|
|
1329
|
+
const clearTimer = () => {
|
|
1330
|
+
if (timer) {
|
|
1331
|
+
clearInterval(timer);
|
|
1332
|
+
timer = null;
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
const reset = () => {
|
|
1336
|
+
clearTimer();
|
|
1337
|
+
lastTime = 0;
|
|
1338
|
+
};
|
|
1339
|
+
return Object.assign(function (...args) {
|
|
1340
|
+
const now = Date.now();
|
|
1341
|
+
const timeGap = now - lastTime - delay;
|
|
1342
|
+
if (timeGap >= 0) {
|
|
1343
|
+
lastTime = now;
|
|
1344
|
+
clearTimer();
|
|
1345
|
+
}
|
|
1346
|
+
if (timeGap >= 0 && leading) {
|
|
1347
|
+
fn.apply(this, args);
|
|
1348
|
+
}
|
|
1349
|
+
else if (timeGap >= 0 || (timeGap < 0 && trailing && !timer)) {
|
|
1350
|
+
timer = setTimeout(() => {
|
|
1351
|
+
lastTime = Date.now();
|
|
1352
|
+
timer = null;
|
|
1353
|
+
fn.apply(this, args);
|
|
1354
|
+
}, timeGap >= 0 ? delay : -timeGap);
|
|
1355
|
+
}
|
|
1356
|
+
}, { reset });
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
function debounce(fn, delay, options) {
|
|
1360
|
+
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1361
|
+
throw new Error('Invalid delay parameter');
|
|
1362
|
+
}
|
|
1363
|
+
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false }, options));
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1282
1366
|
function _cloneArray(obj, map, cloner, ...args) {
|
|
1283
1367
|
const res = obj.slice();
|
|
1284
1368
|
map.set(obj, res);
|
|
@@ -1356,7 +1440,7 @@ function _deepClone(obj, map, options) {
|
|
|
1356
1440
|
map.set(obj, res);
|
|
1357
1441
|
}
|
|
1358
1442
|
else if (obj instanceof DataView) {
|
|
1359
|
-
res = new DataView(_cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
|
|
1443
|
+
res = new DataView(map.has(obj.buffer) ? map.get(obj.buffer) : _cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
|
|
1360
1444
|
map.set(obj, res);
|
|
1361
1445
|
}
|
|
1362
1446
|
else if (isWrapperObject(obj)) {
|
|
@@ -1452,10 +1536,65 @@ function isEmpty(value) {
|
|
|
1452
1536
|
return isNaN(value.getTime());
|
|
1453
1537
|
if (isSet(value) || isMap(value))
|
|
1454
1538
|
return !value.size;
|
|
1455
|
-
|
|
1539
|
+
for (const key in value) {
|
|
1540
|
+
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
return true;
|
|
1456
1544
|
}
|
|
1457
1545
|
}
|
|
1458
1546
|
|
|
1547
|
+
function _getKey(args) {
|
|
1548
|
+
function toString(item) {
|
|
1549
|
+
if (isBigInt(item))
|
|
1550
|
+
return String(item) + 'n';
|
|
1551
|
+
if (isRegExp(item))
|
|
1552
|
+
return 'RegExp' + String(item);
|
|
1553
|
+
if (isDate(item))
|
|
1554
|
+
return 'Date' + item.toISOString();
|
|
1555
|
+
try {
|
|
1556
|
+
return JSON.stringify(item);
|
|
1557
|
+
}
|
|
1558
|
+
catch (e) {
|
|
1559
|
+
return String(item);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
let res = 'ForeSlashMemoKey:[';
|
|
1563
|
+
for (let i = 0; i < args.length; i++) {
|
|
1564
|
+
res += toString(args[i]) + ',';
|
|
1565
|
+
}
|
|
1566
|
+
return res + ']';
|
|
1567
|
+
}
|
|
1568
|
+
function memo(fn, options) {
|
|
1569
|
+
const map = new Map();
|
|
1570
|
+
const getKey = (options === null || options === void 0 ? void 0 : options.getKey) ? options.getKey : _getKey;
|
|
1571
|
+
const setTtl = (options === null || options === void 0 ? void 0 : options.ttl) ? options.ttl : 0;
|
|
1572
|
+
const setCount = (options === null || options === void 0 ? void 0 : options.count) ? options.count : 0;
|
|
1573
|
+
return function (...args) {
|
|
1574
|
+
const key = getKey(args);
|
|
1575
|
+
if (map.has(key)) {
|
|
1576
|
+
const item = map.get(key);
|
|
1577
|
+
const { res, ttl, count } = item;
|
|
1578
|
+
const isValidCache = ttl >= Date.now() && count > 0;
|
|
1579
|
+
item.count -= 1;
|
|
1580
|
+
if (item.count <= 0)
|
|
1581
|
+
map.delete(key);
|
|
1582
|
+
if (ttl < Date.now())
|
|
1583
|
+
map.delete(key);
|
|
1584
|
+
if (isValidCache)
|
|
1585
|
+
return res;
|
|
1586
|
+
}
|
|
1587
|
+
const res = fn.apply(this, args);
|
|
1588
|
+
const memoItem = { res, ttl: Infinity, count: Infinity };
|
|
1589
|
+
if (setCount > 0)
|
|
1590
|
+
memoItem.count = setCount;
|
|
1591
|
+
if (setTtl > 0)
|
|
1592
|
+
memoItem.ttl = Date.now() + setTtl;
|
|
1593
|
+
map.set(key, memoItem);
|
|
1594
|
+
return res;
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1459
1598
|
function not(value) {
|
|
1460
1599
|
return !Boolean(value);
|
|
1461
1600
|
}
|
|
@@ -1488,6 +1627,13 @@ function pipe(...pipeFunc) {
|
|
|
1488
1627
|
};
|
|
1489
1628
|
}
|
|
1490
1629
|
|
|
1630
|
+
function throttle(fn, delay, options) {
|
|
1631
|
+
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1632
|
+
throw new Error('Invalid delay parameter');
|
|
1633
|
+
}
|
|
1634
|
+
return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1491
1637
|
exports._ = _;
|
|
1492
1638
|
exports.acceptableFileName = acceptableFileName;
|
|
1493
1639
|
exports.acceptableFileType = acceptableFileType;
|
|
@@ -1497,8 +1643,10 @@ exports.caseConvert = caseConvert;
|
|
|
1497
1643
|
exports.caseKebab = caseKebab;
|
|
1498
1644
|
exports.casePascal = casePascal;
|
|
1499
1645
|
exports.caseSnake = caseSnake;
|
|
1646
|
+
exports.clamp = clamp;
|
|
1500
1647
|
exports.compose = compose;
|
|
1501
1648
|
exports.curry = _curryMore;
|
|
1649
|
+
exports.debounce = debounce;
|
|
1502
1650
|
exports.deepClone = deepClone;
|
|
1503
1651
|
exports.fastClone = fastClone;
|
|
1504
1652
|
exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
|
|
@@ -1554,6 +1702,7 @@ exports.isWrapperObject = isWrapperObject;
|
|
|
1554
1702
|
exports.isWrapperString = isWrapperString;
|
|
1555
1703
|
exports.isWrapperSymbol = isWrapperSymbol;
|
|
1556
1704
|
exports.kebabCase = kebabCase;
|
|
1705
|
+
exports.memo = memo;
|
|
1557
1706
|
exports.noop = noop;
|
|
1558
1707
|
exports.not = not;
|
|
1559
1708
|
exports.pascalCase = pascalCase;
|
|
@@ -1567,10 +1716,12 @@ exports.randomInt = randomInt;
|
|
|
1567
1716
|
exports.randomIntFloor = randomIntFloor;
|
|
1568
1717
|
exports.randomString = randomString;
|
|
1569
1718
|
exports.range = range;
|
|
1719
|
+
exports.remove = remove;
|
|
1570
1720
|
exports.shuffle = shuffle;
|
|
1571
1721
|
exports.sleep = sleep;
|
|
1572
1722
|
exports.snakeCase = snakeCase;
|
|
1573
1723
|
exports.splitWords = splitWords;
|
|
1724
|
+
exports.throttle = throttle;
|
|
1574
1725
|
exports.titleCase = titleCase;
|
|
1575
1726
|
exports.tryit = tryit;
|
|
1576
1727
|
exports.ulid = ulid;
|
package/lib/index.d.ts
CHANGED
|
@@ -17,6 +17,17 @@ type RangeOptions<T> = {
|
|
|
17
17
|
* @version 0.2.0
|
|
18
18
|
*/
|
|
19
19
|
declare function range(start: number, end: number): number[];
|
|
20
|
+
/**
|
|
21
|
+
* 根据目标值生成一个数组, 步长默认为 1
|
|
22
|
+
* @param target 目标值
|
|
23
|
+
* @example
|
|
24
|
+
* ```js
|
|
25
|
+
* range(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
26
|
+
* range(-10) // [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
|
|
27
|
+
* ```
|
|
28
|
+
* @version 0.2.1
|
|
29
|
+
*/
|
|
30
|
+
declare function range(target: number): number[];
|
|
20
31
|
/**
|
|
21
32
|
* 根据起止值生成一个数组, 步长默认为 1
|
|
22
33
|
* @param start 开始值
|
|
@@ -46,6 +57,26 @@ declare function range(start: number, end: number, step?: number): number[];
|
|
|
46
57
|
*/
|
|
47
58
|
declare function range<T = number>(start: number, end: number, options?: RangeOptions<T>): T[];
|
|
48
59
|
|
|
60
|
+
/**
|
|
61
|
+
* 根据给定的条件来移除数组中的元素(不会影响原数组)
|
|
62
|
+
* @param arr 需要移除部分元素的数组
|
|
63
|
+
* @param item 需要移除的元素, 或判断某个元素是否应该移除的函数
|
|
64
|
+
* @returns 返回移除后的新数组
|
|
65
|
+
* @example
|
|
66
|
+
* ```js
|
|
67
|
+
* // 基本用法
|
|
68
|
+
* remove([1, 2, 3, 4, 5], 5) // [1, 2, 3, 4]
|
|
69
|
+
* remove([1, 2, 3, 4, 5], (num) => num % 2) // [1, 3, 5]
|
|
70
|
+
* // 可以传入多个过滤条件
|
|
71
|
+
* remove([1, 2, 3, 4, 5], 3, 4, 5) // [1, 2]
|
|
72
|
+
* remove([1, 2, 3, 4, 5], (num) => num % 2, (num) => num > 4) // [1, 3]
|
|
73
|
+
* // 可以混合传入过滤条件
|
|
74
|
+
* remove([1, 2, 3, 4, 5], (num) => num % 2, (num) => num > 4, 3) // [1]
|
|
75
|
+
* ```
|
|
76
|
+
* @version 0.2.2
|
|
77
|
+
*/
|
|
78
|
+
declare function remove<T>(arr: ArrayLike<T>, ...item: (T | ((val: T) => unknown))[]): T[];
|
|
79
|
+
|
|
49
80
|
/**
|
|
50
81
|
* 延迟一定时间
|
|
51
82
|
* @param time 延迟时间, 单位为毫秒(ms), 默认为 `1000` (即 1 秒)
|
|
@@ -690,6 +721,32 @@ declare function isWrapperSymbol(value: unknown): value is Symbol;
|
|
|
690
721
|
*/
|
|
691
722
|
declare function isWrapperBigInt(value: unknown): value is BigInt;
|
|
692
723
|
|
|
724
|
+
/**
|
|
725
|
+
* 将一个数字限制在指定范围内
|
|
726
|
+
* @param num 初始值
|
|
727
|
+
* @param min 最小值, 没有默认值, 初始值小于最小值或初始值不为数字时返回最小值
|
|
728
|
+
* @param max 最大值, 没有默认值, 初始值大于最大值时返回最大值
|
|
729
|
+
* @param options 配置项, 可以配置默认值等
|
|
730
|
+
* - `default` 默认值, 如果初始值不在范围内, 则返回默认值
|
|
731
|
+
* - `defaultMin` 初始值小于最小值时返回该值, 覆盖 `default` 参数
|
|
732
|
+
* - `defaultMax` 初始值大于最大值时返回该值
|
|
733
|
+
* @returns 返回一个在指定范围内的数字
|
|
734
|
+
* @example
|
|
735
|
+
* ```js
|
|
736
|
+
* clamp(5, 0, 10) // 5
|
|
737
|
+
* clamp(15, 0, 10) // 10
|
|
738
|
+
* clamp(-5, 0, 10) // 0
|
|
739
|
+
* clamp(5, 0, 10, { default: 6 }) // 5
|
|
740
|
+
* clamp(15, 0, 10, { default: 6 }) // 6
|
|
741
|
+
* clamp(-5, 0, 10, { default: 6 }) // 6
|
|
742
|
+
* ```
|
|
743
|
+
*/
|
|
744
|
+
declare function clamp(num: number, min: number, max: number, options?: {
|
|
745
|
+
default?: number;
|
|
746
|
+
defaultMin?: number;
|
|
747
|
+
defaultMax?: number;
|
|
748
|
+
}): number;
|
|
749
|
+
|
|
693
750
|
/**
|
|
694
751
|
* 根据文件名称判断是否匹配支持的文件类型,需要注意 `.C` 与 `.c` 的区别
|
|
695
752
|
* - `text/x-c++src` 对应 `.C`
|
|
@@ -1260,6 +1317,26 @@ declare function _curryMore<Arg1, Arg2, Res>(fn: (arg1: Arg1, arg2: Arg2) => Res
|
|
|
1260
1317
|
declare function _curryMore<Arg1, Arg2, Arg3, Res>(fn: (arg1: Arg1, arg2: Arg2, arg3: Arg3) => Res): F.Curry<(arg1: Arg1, arg2: Arg2, arg3: Arg3) => Res>;
|
|
1261
1318
|
declare function _curryMore<Args extends Array<any>, Res>(fn: (...args: Args) => Res): F.Curry<(...args: Args) => Res>;
|
|
1262
1319
|
|
|
1320
|
+
interface ThrottleOptions {
|
|
1321
|
+
/** 节流时触发的最后一次调用是否执行, 默认为否 */
|
|
1322
|
+
trailing?: boolean;
|
|
1323
|
+
/** 第一次触发是否直接执行, 默认为是 */
|
|
1324
|
+
leading?: boolean;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/**
|
|
1328
|
+
* 将一个高频调用的函数处理为防抖函数, 一段时间内多次调用会合并为一次
|
|
1329
|
+
* - 比如说 `delay` 设置为 120, 那么方法在 120ms 内多次触发, 也只会在第一次触发的 120ms 后执行一次
|
|
1330
|
+
* @param fn 需要防抖的函数
|
|
1331
|
+
* @param delay 防抖时间间隔, 单位毫秒, 建议 100 以上
|
|
1332
|
+
* @param options 防抖函数的配置, 默认值为 `{ trailing: true, leading: false }`
|
|
1333
|
+
* @returns 一个防抖处理的函数, 你可以使用其上的 `reset` 方法重置节流函数内部状态(会停止计划中的函数执行)
|
|
1334
|
+
* @version 0.2.2
|
|
1335
|
+
*/
|
|
1336
|
+
declare function debounce<T extends any[]>(fn: (...args: T) => any, delay: number, options?: ThrottleOptions): ((this: any, ...args: T) => void) & {
|
|
1337
|
+
reset: () => void;
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1263
1340
|
interface CustomCloner<T = any> {
|
|
1264
1341
|
cloner(val: T, map: Map<any, any>): T;
|
|
1265
1342
|
judger(val: any): boolean;
|
|
@@ -1358,6 +1435,22 @@ declare function fastClone<T>(obj: T, map?: Map<any, any>): T;
|
|
|
1358
1435
|
*/
|
|
1359
1436
|
declare function isEmpty(value: unknown): boolean;
|
|
1360
1437
|
|
|
1438
|
+
/**
|
|
1439
|
+
* 将一个函数记忆化, 多次调用如果参数相同, 则直接返回缓存的结果, 而不会反复执行函数
|
|
1440
|
+
* - 每次运行时会将当前参数处理为 `key`, 相同 `key` 的函数调用将返回相同的结果
|
|
1441
|
+
* @param fn 要缓存的函数
|
|
1442
|
+
* @param options 缓存选项
|
|
1443
|
+
* - `getKey` 自定义 key 的生成规则, 默认使用内部方法生成 key
|
|
1444
|
+
* - `ttl` 缓存的过期时间, 单位毫秒, 为 0 表示不过期, 默认不过期
|
|
1445
|
+
* - `count` 缓存最大使用次数, 为 0 表示不限次数, 默认不限次数
|
|
1446
|
+
* @returns
|
|
1447
|
+
*/
|
|
1448
|
+
declare function memo<TArgs extends any[], TRes>(fn: (...args: TArgs) => TRes, options?: {
|
|
1449
|
+
getKey?: (...args: TArgs) => string | number;
|
|
1450
|
+
ttl?: number;
|
|
1451
|
+
count?: number;
|
|
1452
|
+
}): (this: any, ...args: TArgs) => TRes;
|
|
1453
|
+
|
|
1361
1454
|
/**
|
|
1362
1455
|
* 不做任何操作,返回 `void` ,一般用于函数式编程
|
|
1363
1456
|
* @example
|
|
@@ -1525,4 +1618,17 @@ declare function pipe<PipeArgs extends any[], PipeResult, Mid1, Mid2, Mid3, Mid4
|
|
|
1525
1618
|
declare function pipe<PipeArgs extends any[], PipeResult, Mid1, Mid2, Mid3, Mid4, Mid5, Mid6, Mid7>(...pipeFunc: PipeFuncList8<PipeArgs, PipeResult, Mid1, Mid2, Mid3, Mid4, Mid5, Mid6, Mid7>): (...args: PipeArgs) => PipeResult;
|
|
1526
1619
|
declare function pipe<PipeArgs extends any[], PipeResult, Mid1, Mid2, Mid3, Mid4, Mid5, Mid6, Mid7>(...pipeFunc: PipeFuncListMore<PipeArgs, PipeResult, Mid1, Mid2, Mid3, Mid4, Mid5, Mid6, Mid7>): (...args: PipeArgs) => PipeResult;
|
|
1527
1620
|
|
|
1528
|
-
|
|
1621
|
+
/**
|
|
1622
|
+
* 将一个高频调用的函数处理为节流函数, 一段时间内只会调用一次
|
|
1623
|
+
* - 比如说 `delay` 设置为 120, 那么方法在第一次触发后执行, 随后的 120ms 内多次触发也不会再执行
|
|
1624
|
+
* @param fn 需要节流的函数
|
|
1625
|
+
* @param delay 节流时间间隔, 单位毫秒, 建议 100 以上
|
|
1626
|
+
* @param options 节流函数的配置, 默认值为 `{ trailing: false, leading: true }`
|
|
1627
|
+
* @returns 一个节流处理的函数, 你可以使用其上的 `reset` 方法重置节流函数内部状态(会停止计划中的函数执行)
|
|
1628
|
+
* @version 0.2.2
|
|
1629
|
+
*/
|
|
1630
|
+
declare function throttle<T extends any[]>(fn: (...args: T) => any, delay: number, options?: ThrottleOptions): ((this: any, ...args: T) => void) & {
|
|
1631
|
+
reset: () => void;
|
|
1632
|
+
};
|
|
1633
|
+
|
|
1634
|
+
export { type CloneOptions, type CustomCloner, type RangeOptions, type TypedArray, _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uuidNil, uuidV4, withResolvers };
|
package/lib/index.mjs
CHANGED
|
@@ -10,6 +10,12 @@ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
|
10
10
|
See the Mulan PSL v2 for more details.
|
|
11
11
|
*/
|
|
12
12
|
function range(start, end, stepOrOptions) {
|
|
13
|
+
if (!isFinite(start))
|
|
14
|
+
throw new Error('start must be finite');
|
|
15
|
+
if (end == null)
|
|
16
|
+
return range(0, start);
|
|
17
|
+
if (!isFinite(end))
|
|
18
|
+
throw new Error('end must be finite');
|
|
13
19
|
let step = 1;
|
|
14
20
|
let getter = null;
|
|
15
21
|
if (typeof stepOrOptions === 'number') {
|
|
@@ -28,8 +34,6 @@ function range(start, end, stepOrOptions) {
|
|
|
28
34
|
throw new Error('step must be finite');
|
|
29
35
|
if (step === 0)
|
|
30
36
|
throw new Error('step must not be 0');
|
|
31
|
-
if (!isFinite(start) || !isFinite(end))
|
|
32
|
-
throw new Error('start and end must be finite');
|
|
33
37
|
if ((start > end && step > 0) || (start < end && step < 0))
|
|
34
38
|
step = -step;
|
|
35
39
|
const res = [];
|
|
@@ -41,6 +45,26 @@ function range(start, end, stepOrOptions) {
|
|
|
41
45
|
return res;
|
|
42
46
|
}
|
|
43
47
|
|
|
48
|
+
function remove(arr, ...item) {
|
|
49
|
+
const removeSet = new Set();
|
|
50
|
+
const judgerList = [];
|
|
51
|
+
for (let i = 0; i < item.length; i++) {
|
|
52
|
+
const cond = item[i];
|
|
53
|
+
if (typeof cond === 'function')
|
|
54
|
+
judgerList.push(cond);
|
|
55
|
+
else
|
|
56
|
+
removeSet.add(cond);
|
|
57
|
+
}
|
|
58
|
+
const res = [];
|
|
59
|
+
for (let i = 0; i < arr.length; i++) {
|
|
60
|
+
const el = arr[i];
|
|
61
|
+
if (removeSet.has(el) || judgerList.some((judger) => judger(el)))
|
|
62
|
+
continue;
|
|
63
|
+
res.push(el);
|
|
64
|
+
}
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
67
|
+
|
|
44
68
|
function sleep(time = 1000) {
|
|
45
69
|
return new Promise((res) => {
|
|
46
70
|
setTimeout(res, time);
|
|
@@ -279,6 +303,23 @@ function withResolvers(PromiseLike = Promise) {
|
|
|
279
303
|
return { promise, resolve, reject };
|
|
280
304
|
}
|
|
281
305
|
|
|
306
|
+
function clamp(num, min, max, options) {
|
|
307
|
+
var _a, _b;
|
|
308
|
+
if (isNaN(min))
|
|
309
|
+
throw new Error('Invalid min parameter');
|
|
310
|
+
if (isNaN(max))
|
|
311
|
+
throw new Error('Invalid max parameter');
|
|
312
|
+
if (max < min) {
|
|
313
|
+
[min, max] = [max, min];
|
|
314
|
+
}
|
|
315
|
+
const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
|
|
316
|
+
const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
|
|
317
|
+
const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
|
|
318
|
+
if (isNaN(num))
|
|
319
|
+
return defaultMin;
|
|
320
|
+
return num < min ? defaultMin : num > max ? defaultMax : num;
|
|
321
|
+
}
|
|
322
|
+
|
|
282
323
|
const mimeMap = {
|
|
283
324
|
application: {
|
|
284
325
|
acrobat: ['pdf'],
|
|
@@ -1277,6 +1318,49 @@ function _curryMore(fn) {
|
|
|
1277
1318
|
}
|
|
1278
1319
|
}
|
|
1279
1320
|
|
|
1321
|
+
function _throttle(fn, delay, options) {
|
|
1322
|
+
var _a, _b;
|
|
1323
|
+
const trailing = (_a = options === null || options === void 0 ? void 0 : options.trailing) !== null && _a !== void 0 ? _a : false;
|
|
1324
|
+
const leading = (_b = options === null || options === void 0 ? void 0 : options.leading) !== null && _b !== void 0 ? _b : true;
|
|
1325
|
+
let timer = null;
|
|
1326
|
+
let lastTime = 0;
|
|
1327
|
+
const clearTimer = () => {
|
|
1328
|
+
if (timer) {
|
|
1329
|
+
clearInterval(timer);
|
|
1330
|
+
timer = null;
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
const reset = () => {
|
|
1334
|
+
clearTimer();
|
|
1335
|
+
lastTime = 0;
|
|
1336
|
+
};
|
|
1337
|
+
return Object.assign(function (...args) {
|
|
1338
|
+
const now = Date.now();
|
|
1339
|
+
const timeGap = now - lastTime - delay;
|
|
1340
|
+
if (timeGap >= 0) {
|
|
1341
|
+
lastTime = now;
|
|
1342
|
+
clearTimer();
|
|
1343
|
+
}
|
|
1344
|
+
if (timeGap >= 0 && leading) {
|
|
1345
|
+
fn.apply(this, args);
|
|
1346
|
+
}
|
|
1347
|
+
else if (timeGap >= 0 || (timeGap < 0 && trailing && !timer)) {
|
|
1348
|
+
timer = setTimeout(() => {
|
|
1349
|
+
lastTime = Date.now();
|
|
1350
|
+
timer = null;
|
|
1351
|
+
fn.apply(this, args);
|
|
1352
|
+
}, timeGap >= 0 ? delay : -timeGap);
|
|
1353
|
+
}
|
|
1354
|
+
}, { reset });
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
function debounce(fn, delay, options) {
|
|
1358
|
+
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1359
|
+
throw new Error('Invalid delay parameter');
|
|
1360
|
+
}
|
|
1361
|
+
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false }, options));
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1280
1364
|
function _cloneArray(obj, map, cloner, ...args) {
|
|
1281
1365
|
const res = obj.slice();
|
|
1282
1366
|
map.set(obj, res);
|
|
@@ -1354,7 +1438,7 @@ function _deepClone(obj, map, options) {
|
|
|
1354
1438
|
map.set(obj, res);
|
|
1355
1439
|
}
|
|
1356
1440
|
else if (obj instanceof DataView) {
|
|
1357
|
-
res = new DataView(_cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
|
|
1441
|
+
res = new DataView(map.has(obj.buffer) ? map.get(obj.buffer) : _cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
|
|
1358
1442
|
map.set(obj, res);
|
|
1359
1443
|
}
|
|
1360
1444
|
else if (isWrapperObject(obj)) {
|
|
@@ -1450,10 +1534,65 @@ function isEmpty(value) {
|
|
|
1450
1534
|
return isNaN(value.getTime());
|
|
1451
1535
|
if (isSet(value) || isMap(value))
|
|
1452
1536
|
return !value.size;
|
|
1453
|
-
|
|
1537
|
+
for (const key in value) {
|
|
1538
|
+
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
1539
|
+
return false;
|
|
1540
|
+
}
|
|
1541
|
+
return true;
|
|
1454
1542
|
}
|
|
1455
1543
|
}
|
|
1456
1544
|
|
|
1545
|
+
function _getKey(args) {
|
|
1546
|
+
function toString(item) {
|
|
1547
|
+
if (isBigInt(item))
|
|
1548
|
+
return String(item) + 'n';
|
|
1549
|
+
if (isRegExp(item))
|
|
1550
|
+
return 'RegExp' + String(item);
|
|
1551
|
+
if (isDate(item))
|
|
1552
|
+
return 'Date' + item.toISOString();
|
|
1553
|
+
try {
|
|
1554
|
+
return JSON.stringify(item);
|
|
1555
|
+
}
|
|
1556
|
+
catch (e) {
|
|
1557
|
+
return String(item);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
let res = 'ForeSlashMemoKey:[';
|
|
1561
|
+
for (let i = 0; i < args.length; i++) {
|
|
1562
|
+
res += toString(args[i]) + ',';
|
|
1563
|
+
}
|
|
1564
|
+
return res + ']';
|
|
1565
|
+
}
|
|
1566
|
+
function memo(fn, options) {
|
|
1567
|
+
const map = new Map();
|
|
1568
|
+
const getKey = (options === null || options === void 0 ? void 0 : options.getKey) ? options.getKey : _getKey;
|
|
1569
|
+
const setTtl = (options === null || options === void 0 ? void 0 : options.ttl) ? options.ttl : 0;
|
|
1570
|
+
const setCount = (options === null || options === void 0 ? void 0 : options.count) ? options.count : 0;
|
|
1571
|
+
return function (...args) {
|
|
1572
|
+
const key = getKey(args);
|
|
1573
|
+
if (map.has(key)) {
|
|
1574
|
+
const item = map.get(key);
|
|
1575
|
+
const { res, ttl, count } = item;
|
|
1576
|
+
const isValidCache = ttl >= Date.now() && count > 0;
|
|
1577
|
+
item.count -= 1;
|
|
1578
|
+
if (item.count <= 0)
|
|
1579
|
+
map.delete(key);
|
|
1580
|
+
if (ttl < Date.now())
|
|
1581
|
+
map.delete(key);
|
|
1582
|
+
if (isValidCache)
|
|
1583
|
+
return res;
|
|
1584
|
+
}
|
|
1585
|
+
const res = fn.apply(this, args);
|
|
1586
|
+
const memoItem = { res, ttl: Infinity, count: Infinity };
|
|
1587
|
+
if (setCount > 0)
|
|
1588
|
+
memoItem.count = setCount;
|
|
1589
|
+
if (setTtl > 0)
|
|
1590
|
+
memoItem.ttl = Date.now() + setTtl;
|
|
1591
|
+
map.set(key, memoItem);
|
|
1592
|
+
return res;
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1457
1596
|
function not(value) {
|
|
1458
1597
|
return !Boolean(value);
|
|
1459
1598
|
}
|
|
@@ -1486,4 +1625,11 @@ function pipe(...pipeFunc) {
|
|
|
1486
1625
|
};
|
|
1487
1626
|
}
|
|
1488
1627
|
|
|
1489
|
-
|
|
1628
|
+
function throttle(fn, delay, options) {
|
|
1629
|
+
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1630
|
+
throw new Error('Invalid delay parameter');
|
|
1631
|
+
}
|
|
1632
|
+
return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
export { _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uuidNil, uuidV4, withResolvers };
|
package/lib/index.umd.js
CHANGED
|
@@ -16,6 +16,12 @@ See the Mulan PSL v2 for more details.
|
|
|
16
16
|
})(this, (function (exports) { 'use strict';
|
|
17
17
|
|
|
18
18
|
function range(start, end, stepOrOptions) {
|
|
19
|
+
if (!isFinite(start))
|
|
20
|
+
throw new Error('start must be finite');
|
|
21
|
+
if (end == null)
|
|
22
|
+
return range(0, start);
|
|
23
|
+
if (!isFinite(end))
|
|
24
|
+
throw new Error('end must be finite');
|
|
19
25
|
let step = 1;
|
|
20
26
|
let getter = null;
|
|
21
27
|
if (typeof stepOrOptions === 'number') {
|
|
@@ -34,8 +40,6 @@ See the Mulan PSL v2 for more details.
|
|
|
34
40
|
throw new Error('step must be finite');
|
|
35
41
|
if (step === 0)
|
|
36
42
|
throw new Error('step must not be 0');
|
|
37
|
-
if (!isFinite(start) || !isFinite(end))
|
|
38
|
-
throw new Error('start and end must be finite');
|
|
39
43
|
if ((start > end && step > 0) || (start < end && step < 0))
|
|
40
44
|
step = -step;
|
|
41
45
|
const res = [];
|
|
@@ -47,6 +51,26 @@ See the Mulan PSL v2 for more details.
|
|
|
47
51
|
return res;
|
|
48
52
|
}
|
|
49
53
|
|
|
54
|
+
function remove(arr, ...item) {
|
|
55
|
+
const removeSet = new Set();
|
|
56
|
+
const judgerList = [];
|
|
57
|
+
for (let i = 0; i < item.length; i++) {
|
|
58
|
+
const cond = item[i];
|
|
59
|
+
if (typeof cond === 'function')
|
|
60
|
+
judgerList.push(cond);
|
|
61
|
+
else
|
|
62
|
+
removeSet.add(cond);
|
|
63
|
+
}
|
|
64
|
+
const res = [];
|
|
65
|
+
for (let i = 0; i < arr.length; i++) {
|
|
66
|
+
const el = arr[i];
|
|
67
|
+
if (removeSet.has(el) || judgerList.some((judger) => judger(el)))
|
|
68
|
+
continue;
|
|
69
|
+
res.push(el);
|
|
70
|
+
}
|
|
71
|
+
return res;
|
|
72
|
+
}
|
|
73
|
+
|
|
50
74
|
function sleep(time = 1000) {
|
|
51
75
|
return new Promise((res) => {
|
|
52
76
|
setTimeout(res, time);
|
|
@@ -285,6 +309,23 @@ See the Mulan PSL v2 for more details.
|
|
|
285
309
|
return { promise, resolve, reject };
|
|
286
310
|
}
|
|
287
311
|
|
|
312
|
+
function clamp(num, min, max, options) {
|
|
313
|
+
var _a, _b;
|
|
314
|
+
if (isNaN(min))
|
|
315
|
+
throw new Error('Invalid min parameter');
|
|
316
|
+
if (isNaN(max))
|
|
317
|
+
throw new Error('Invalid max parameter');
|
|
318
|
+
if (max < min) {
|
|
319
|
+
[min, max] = [max, min];
|
|
320
|
+
}
|
|
321
|
+
const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
|
|
322
|
+
const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
|
|
323
|
+
const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
|
|
324
|
+
if (isNaN(num))
|
|
325
|
+
return defaultMin;
|
|
326
|
+
return num < min ? defaultMin : num > max ? defaultMax : num;
|
|
327
|
+
}
|
|
328
|
+
|
|
288
329
|
const mimeMap = {
|
|
289
330
|
application: {
|
|
290
331
|
acrobat: ['pdf'],
|
|
@@ -1283,6 +1324,49 @@ See the Mulan PSL v2 for more details.
|
|
|
1283
1324
|
}
|
|
1284
1325
|
}
|
|
1285
1326
|
|
|
1327
|
+
function _throttle(fn, delay, options) {
|
|
1328
|
+
var _a, _b;
|
|
1329
|
+
const trailing = (_a = options === null || options === void 0 ? void 0 : options.trailing) !== null && _a !== void 0 ? _a : false;
|
|
1330
|
+
const leading = (_b = options === null || options === void 0 ? void 0 : options.leading) !== null && _b !== void 0 ? _b : true;
|
|
1331
|
+
let timer = null;
|
|
1332
|
+
let lastTime = 0;
|
|
1333
|
+
const clearTimer = () => {
|
|
1334
|
+
if (timer) {
|
|
1335
|
+
clearInterval(timer);
|
|
1336
|
+
timer = null;
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
const reset = () => {
|
|
1340
|
+
clearTimer();
|
|
1341
|
+
lastTime = 0;
|
|
1342
|
+
};
|
|
1343
|
+
return Object.assign(function (...args) {
|
|
1344
|
+
const now = Date.now();
|
|
1345
|
+
const timeGap = now - lastTime - delay;
|
|
1346
|
+
if (timeGap >= 0) {
|
|
1347
|
+
lastTime = now;
|
|
1348
|
+
clearTimer();
|
|
1349
|
+
}
|
|
1350
|
+
if (timeGap >= 0 && leading) {
|
|
1351
|
+
fn.apply(this, args);
|
|
1352
|
+
}
|
|
1353
|
+
else if (timeGap >= 0 || (timeGap < 0 && trailing && !timer)) {
|
|
1354
|
+
timer = setTimeout(() => {
|
|
1355
|
+
lastTime = Date.now();
|
|
1356
|
+
timer = null;
|
|
1357
|
+
fn.apply(this, args);
|
|
1358
|
+
}, timeGap >= 0 ? delay : -timeGap);
|
|
1359
|
+
}
|
|
1360
|
+
}, { reset });
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function debounce(fn, delay, options) {
|
|
1364
|
+
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1365
|
+
throw new Error('Invalid delay parameter');
|
|
1366
|
+
}
|
|
1367
|
+
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false }, options));
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1286
1370
|
function _cloneArray(obj, map, cloner, ...args) {
|
|
1287
1371
|
const res = obj.slice();
|
|
1288
1372
|
map.set(obj, res);
|
|
@@ -1360,7 +1444,7 @@ See the Mulan PSL v2 for more details.
|
|
|
1360
1444
|
map.set(obj, res);
|
|
1361
1445
|
}
|
|
1362
1446
|
else if (obj instanceof DataView) {
|
|
1363
|
-
res = new DataView(_cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
|
|
1447
|
+
res = new DataView(map.has(obj.buffer) ? map.get(obj.buffer) : _cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
|
|
1364
1448
|
map.set(obj, res);
|
|
1365
1449
|
}
|
|
1366
1450
|
else if (isWrapperObject(obj)) {
|
|
@@ -1456,10 +1540,65 @@ See the Mulan PSL v2 for more details.
|
|
|
1456
1540
|
return isNaN(value.getTime());
|
|
1457
1541
|
if (isSet(value) || isMap(value))
|
|
1458
1542
|
return !value.size;
|
|
1459
|
-
|
|
1543
|
+
for (const key in value) {
|
|
1544
|
+
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
1545
|
+
return false;
|
|
1546
|
+
}
|
|
1547
|
+
return true;
|
|
1460
1548
|
}
|
|
1461
1549
|
}
|
|
1462
1550
|
|
|
1551
|
+
function _getKey(args) {
|
|
1552
|
+
function toString(item) {
|
|
1553
|
+
if (isBigInt(item))
|
|
1554
|
+
return String(item) + 'n';
|
|
1555
|
+
if (isRegExp(item))
|
|
1556
|
+
return 'RegExp' + String(item);
|
|
1557
|
+
if (isDate(item))
|
|
1558
|
+
return 'Date' + item.toISOString();
|
|
1559
|
+
try {
|
|
1560
|
+
return JSON.stringify(item);
|
|
1561
|
+
}
|
|
1562
|
+
catch (e) {
|
|
1563
|
+
return String(item);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
let res = 'ForeSlashMemoKey:[';
|
|
1567
|
+
for (let i = 0; i < args.length; i++) {
|
|
1568
|
+
res += toString(args[i]) + ',';
|
|
1569
|
+
}
|
|
1570
|
+
return res + ']';
|
|
1571
|
+
}
|
|
1572
|
+
function memo(fn, options) {
|
|
1573
|
+
const map = new Map();
|
|
1574
|
+
const getKey = (options === null || options === void 0 ? void 0 : options.getKey) ? options.getKey : _getKey;
|
|
1575
|
+
const setTtl = (options === null || options === void 0 ? void 0 : options.ttl) ? options.ttl : 0;
|
|
1576
|
+
const setCount = (options === null || options === void 0 ? void 0 : options.count) ? options.count : 0;
|
|
1577
|
+
return function (...args) {
|
|
1578
|
+
const key = getKey(args);
|
|
1579
|
+
if (map.has(key)) {
|
|
1580
|
+
const item = map.get(key);
|
|
1581
|
+
const { res, ttl, count } = item;
|
|
1582
|
+
const isValidCache = ttl >= Date.now() && count > 0;
|
|
1583
|
+
item.count -= 1;
|
|
1584
|
+
if (item.count <= 0)
|
|
1585
|
+
map.delete(key);
|
|
1586
|
+
if (ttl < Date.now())
|
|
1587
|
+
map.delete(key);
|
|
1588
|
+
if (isValidCache)
|
|
1589
|
+
return res;
|
|
1590
|
+
}
|
|
1591
|
+
const res = fn.apply(this, args);
|
|
1592
|
+
const memoItem = { res, ttl: Infinity, count: Infinity };
|
|
1593
|
+
if (setCount > 0)
|
|
1594
|
+
memoItem.count = setCount;
|
|
1595
|
+
if (setTtl > 0)
|
|
1596
|
+
memoItem.ttl = Date.now() + setTtl;
|
|
1597
|
+
map.set(key, memoItem);
|
|
1598
|
+
return res;
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1463
1602
|
function not(value) {
|
|
1464
1603
|
return !Boolean(value);
|
|
1465
1604
|
}
|
|
@@ -1492,6 +1631,13 @@ See the Mulan PSL v2 for more details.
|
|
|
1492
1631
|
};
|
|
1493
1632
|
}
|
|
1494
1633
|
|
|
1634
|
+
function throttle(fn, delay, options) {
|
|
1635
|
+
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1636
|
+
throw new Error('Invalid delay parameter');
|
|
1637
|
+
}
|
|
1638
|
+
return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1495
1641
|
exports._ = _;
|
|
1496
1642
|
exports.acceptableFileName = acceptableFileName;
|
|
1497
1643
|
exports.acceptableFileType = acceptableFileType;
|
|
@@ -1501,8 +1647,10 @@ See the Mulan PSL v2 for more details.
|
|
|
1501
1647
|
exports.caseKebab = caseKebab;
|
|
1502
1648
|
exports.casePascal = casePascal;
|
|
1503
1649
|
exports.caseSnake = caseSnake;
|
|
1650
|
+
exports.clamp = clamp;
|
|
1504
1651
|
exports.compose = compose;
|
|
1505
1652
|
exports.curry = _curryMore;
|
|
1653
|
+
exports.debounce = debounce;
|
|
1506
1654
|
exports.deepClone = deepClone;
|
|
1507
1655
|
exports.fastClone = fastClone;
|
|
1508
1656
|
exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
|
|
@@ -1558,6 +1706,7 @@ See the Mulan PSL v2 for more details.
|
|
|
1558
1706
|
exports.isWrapperString = isWrapperString;
|
|
1559
1707
|
exports.isWrapperSymbol = isWrapperSymbol;
|
|
1560
1708
|
exports.kebabCase = kebabCase;
|
|
1709
|
+
exports.memo = memo;
|
|
1561
1710
|
exports.noop = noop;
|
|
1562
1711
|
exports.not = not;
|
|
1563
1712
|
exports.pascalCase = pascalCase;
|
|
@@ -1571,10 +1720,12 @@ See the Mulan PSL v2 for more details.
|
|
|
1571
1720
|
exports.randomIntFloor = randomIntFloor;
|
|
1572
1721
|
exports.randomString = randomString;
|
|
1573
1722
|
exports.range = range;
|
|
1723
|
+
exports.remove = remove;
|
|
1574
1724
|
exports.shuffle = shuffle;
|
|
1575
1725
|
exports.sleep = sleep;
|
|
1576
1726
|
exports.snakeCase = snakeCase;
|
|
1577
1727
|
exports.splitWords = splitWords;
|
|
1728
|
+
exports.throttle = throttle;
|
|
1578
1729
|
exports.titleCase = titleCase;
|
|
1579
1730
|
exports.tryit = tryit;
|
|
1580
1731
|
exports.ulid = ulid;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "foreslash",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Foreslash is a Javascript utilities lib which contains plenty of practical functions.",
|
|
5
5
|
"author": "moushu",
|
|
6
6
|
"license": "Mulan PSL v2",
|
|
@@ -21,13 +21,16 @@
|
|
|
21
21
|
".": {
|
|
22
22
|
"import": "./lib/index.mjs",
|
|
23
23
|
"require": "./lib/index.cmn.cjs",
|
|
24
|
-
"types": "./
|
|
24
|
+
"types": "./lib/index.d.ts"
|
|
25
25
|
},
|
|
26
26
|
"./umd": "./lib/index.umd.js"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"lib",
|
|
30
|
-
"README.md"
|
|
30
|
+
"README.EN.md",
|
|
31
|
+
"CHANGELOG.md",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
31
34
|
],
|
|
32
35
|
"scripts": {
|
|
33
36
|
"dev": "rollup -c -w",
|