@planet-matrix/mobius-model 0.5.0 → 0.6.0
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 +24 -0
- package/README.md +123 -36
- package/dist/index.js +45 -4
- package/dist/index.js.map +183 -11
- package/oxlint.config.ts +6 -0
- package/package.json +16 -10
- package/src/abort/README.md +92 -0
- package/src/abort/abort-manager.ts +278 -0
- package/src/abort/abort-signal-listener-manager.ts +81 -0
- package/src/abort/index.ts +2 -0
- package/src/basic/README.md +69 -118
- package/src/basic/function.ts +81 -62
- package/src/basic/is.ts +152 -71
- package/src/basic/promise.ts +29 -8
- package/src/basic/string.ts +2 -33
- package/src/color/README.md +105 -0
- package/src/color/index.ts +3 -0
- package/src/color/internal.ts +42 -0
- package/src/color/rgb/analyze.ts +236 -0
- package/src/color/rgb/construct.ts +130 -0
- package/src/color/rgb/convert.ts +227 -0
- package/src/color/rgb/derive.ts +303 -0
- package/src/color/rgb/index.ts +6 -0
- package/src/color/rgb/internal.ts +208 -0
- package/src/color/rgb/parse.ts +302 -0
- package/src/color/rgb/serialize.ts +144 -0
- package/src/color/types.ts +57 -0
- package/src/color/xyz/analyze.ts +80 -0
- package/src/color/xyz/construct.ts +19 -0
- package/src/color/xyz/convert.ts +71 -0
- package/src/color/xyz/index.ts +3 -0
- package/src/color/xyz/internal.ts +23 -0
- package/src/css/README.md +93 -0
- package/src/css/class.ts +559 -0
- package/src/css/index.ts +1 -0
- package/src/encoding/README.md +66 -79
- package/src/encoding/base64.ts +13 -4
- package/src/environment/README.md +97 -0
- package/src/environment/basic.ts +26 -0
- package/src/environment/device.ts +311 -0
- package/src/environment/feature.ts +285 -0
- package/src/environment/geo.ts +337 -0
- package/src/environment/index.ts +7 -0
- package/src/environment/runtime.ts +400 -0
- package/src/environment/snapshot.ts +60 -0
- package/src/environment/variable.ts +239 -0
- package/src/event/README.md +90 -0
- package/src/event/class-event-proxy.ts +228 -0
- package/src/event/common.ts +19 -0
- package/src/event/event-manager.ts +203 -0
- package/src/event/index.ts +4 -0
- package/src/event/instance-event-proxy.ts +186 -0
- package/src/event/internal.ts +24 -0
- package/src/exception/README.md +96 -0
- package/src/exception/browser.ts +219 -0
- package/src/exception/index.ts +4 -0
- package/src/exception/nodejs.ts +169 -0
- package/src/exception/normalize.ts +106 -0
- package/src/exception/types.ts +99 -0
- package/src/identifier/README.md +92 -0
- package/src/identifier/id.ts +119 -0
- package/src/identifier/index.ts +2 -0
- package/src/identifier/uuid.ts +187 -0
- package/src/index.ts +16 -1
- package/src/log/README.md +79 -0
- package/src/log/index.ts +5 -0
- package/src/log/log-emitter.ts +72 -0
- package/src/log/log-record.ts +10 -0
- package/src/log/log-scheduler.ts +74 -0
- package/src/log/log-type.ts +8 -0
- package/src/log/logger.ts +543 -0
- package/src/orchestration/README.md +89 -0
- package/src/orchestration/coordination/barrier.ts +214 -0
- package/src/orchestration/coordination/count-down-latch.ts +215 -0
- package/src/orchestration/coordination/errors.ts +98 -0
- package/src/orchestration/coordination/index.ts +16 -0
- package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
- package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
- package/src/orchestration/coordination/keyed-lock.ts +168 -0
- package/src/orchestration/coordination/mutex.ts +257 -0
- package/src/orchestration/coordination/permit.ts +127 -0
- package/src/orchestration/coordination/read-write-lock.ts +444 -0
- package/src/orchestration/coordination/semaphore.ts +280 -0
- package/src/orchestration/index.ts +1 -0
- package/src/random/README.md +55 -86
- package/src/random/index.ts +1 -1
- package/src/random/string.ts +35 -0
- package/src/reactor/README.md +4 -0
- package/src/reactor/reactor-core/primitive.ts +9 -9
- package/src/reactor/reactor-core/reactive-system.ts +5 -5
- package/src/singleton/README.md +79 -0
- package/src/singleton/factory.ts +55 -0
- package/src/singleton/index.ts +2 -0
- package/src/singleton/manager.ts +204 -0
- package/src/storage/README.md +107 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/table.ts +449 -0
- package/src/timer/README.md +86 -0
- package/src/timer/expiration/expiration-manager.ts +594 -0
- package/src/timer/expiration/index.ts +3 -0
- package/src/timer/expiration/min-heap.ts +208 -0
- package/src/timer/expiration/remaining-manager.ts +241 -0
- package/src/timer/index.ts +1 -0
- package/src/type/README.md +54 -307
- package/src/type/class.ts +2 -2
- package/src/type/index.ts +14 -14
- package/src/type/is.ts +265 -2
- package/src/type/object.ts +37 -0
- package/src/type/string.ts +7 -2
- package/src/type/tuple.ts +6 -6
- package/src/type/union.ts +16 -0
- package/src/web/README.md +77 -0
- package/src/web/capture.ts +35 -0
- package/src/web/clipboard.ts +97 -0
- package/src/web/dom.ts +117 -0
- package/src/web/download.ts +16 -0
- package/src/web/event.ts +46 -0
- package/src/web/index.ts +10 -0
- package/src/web/local-storage.ts +113 -0
- package/src/web/location.ts +28 -0
- package/src/web/permission.ts +172 -0
- package/src/web/script-loader.ts +432 -0
- package/tests/unit/abort/abort-manager.spec.ts +225 -0
- package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
- package/tests/unit/basic/array.spec.ts +1 -1
- package/tests/unit/basic/stream.spec.ts +1 -1
- package/tests/unit/basic/string.spec.ts +0 -9
- package/tests/unit/color/rgb/analyze.spec.ts +110 -0
- package/tests/unit/color/rgb/construct.spec.ts +56 -0
- package/tests/unit/color/rgb/convert.spec.ts +60 -0
- package/tests/unit/color/rgb/derive.spec.ts +103 -0
- package/tests/unit/color/rgb/parse.spec.ts +66 -0
- package/tests/unit/color/rgb/serialize.spec.ts +46 -0
- package/tests/unit/color/xyz/analyze.spec.ts +33 -0
- package/tests/unit/color/xyz/construct.spec.ts +10 -0
- package/tests/unit/color/xyz/convert.spec.ts +18 -0
- package/tests/unit/css/class.spec.ts +157 -0
- package/tests/unit/environment/basic.spec.ts +20 -0
- package/tests/unit/environment/device.spec.ts +146 -0
- package/tests/unit/environment/feature.spec.ts +388 -0
- package/tests/unit/environment/geo.spec.ts +111 -0
- package/tests/unit/environment/runtime.spec.ts +364 -0
- package/tests/unit/environment/snapshot.spec.ts +4 -0
- package/tests/unit/environment/variable.spec.ts +190 -0
- package/tests/unit/event/class-event-proxy.spec.ts +225 -0
- package/tests/unit/event/event-manager.spec.ts +246 -0
- package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
- package/tests/unit/exception/browser.spec.ts +213 -0
- package/tests/unit/exception/nodejs.spec.ts +144 -0
- package/tests/unit/exception/normalize.spec.ts +57 -0
- package/tests/unit/identifier/id.spec.ts +71 -0
- package/tests/unit/identifier/uuid.spec.ts +85 -0
- package/tests/unit/log/log-emitter.spec.ts +33 -0
- package/tests/unit/log/log-scheduler.spec.ts +40 -0
- package/tests/unit/log/log-type.spec.ts +7 -0
- package/tests/unit/log/logger.spec.ts +222 -0
- package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
- package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
- package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
- package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
- package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
- package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
- package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
- package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
- package/tests/unit/random/string.spec.ts +11 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
- package/tests/unit/reactor/preact-signal.spec.ts +1 -2
- package/tests/unit/singleton/singleton.spec.ts +49 -0
- package/tests/unit/storage/table.spec.ts +620 -0
- package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
- package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
- package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
- package/.oxlintrc.json +0 -5
- package/src/random/uuid.ts +0 -103
- package/tests/unit/random/uuid.spec.ts +0 -37
package/src/basic/README.md
CHANGED
|
@@ -1,144 +1,95 @@
|
|
|
1
1
|
# Basic
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Description
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Basic 模块提供面向 JavaScript 运行时值(runtime value)的通用基础能力,用于围绕基础类型、内建对象、常见容器与轻量流程控制建立稳定、可组合、低假设的公共语义。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
它关注的不是某个具体业务领域,而是那些可以长期复用的值级操作:判断、转换、裁剪、组合、格式化、调度、异步组织,以及与少量宿主无关接口的桥接。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## For Understanding
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
2. Is: Runtime predicates and type guards (primitives, objects, iterables, DOM/browser targets, and more).
|
|
13
|
-
3. String: String generation, casing conversion, slicing, splitting, and truncation helpers.
|
|
14
|
-
4. Number: Numeric normalization, range constraint, parity checks, and randomization helpers.
|
|
15
|
-
5. Boolean: Boolean conversion and logical operation helpers.
|
|
16
|
-
6. BigInt: BigInt-oriented helpers.
|
|
17
|
-
7. Symbol: Symbol creation, inspection, and conversion helpers.
|
|
18
|
-
8. Array: Array-oriented helpers and transformations.
|
|
19
|
-
9. Object: Object field selection/exclusion, Date-field timestamp conversion, and object utility helpers.
|
|
20
|
-
10. Function: Function composition and execution-control helpers (once, debounce, throttle, memoize, etc.).
|
|
21
|
-
11. Temporal: Date/time formatting, relative-time, and humanization helpers.
|
|
22
|
-
12. Error: Error detection and exception-stringify helpers.
|
|
23
|
-
13. RegExp: RegExp-based validation helpers.
|
|
24
|
-
14. Promise: Promise control-flow, queueing, retry, interval, and forever-loop helpers.
|
|
25
|
-
15. Stream: ReadableStream construction, consumption, and transform helpers.
|
|
26
|
-
16. Enhance: Runtime enhancement helpers (for example, BigInt JSON serialization support).
|
|
11
|
+
理解 Basic 模块时,首先要把握它的核心边界:这里承载的是“值如何被稳定处理”,而不是“宿主环境如何被接入和驱动”。只要某项能力的主要价值在于处理字符串、数字、布尔值、BigInt、符号(Symbol)、数组、对象、函数、Promise、Error、正则表达式(regular expression)、时间值、流(stream)等运行时值,它通常就有机会属于 Basic。
|
|
27
12
|
|
|
28
|
-
|
|
13
|
+
反过来说,如果某项能力的重点已经变成注册全局监听器、驱动宿主生命周期、读取运行时上下文、感知平台能力,或消费宿主级事件源,那么它通常就不再属于 Basic,即使它最后处理的对象仍然表现为某种值。Basic 关心的是值级语义,而不是环境级语义。
|
|
29
14
|
|
|
30
|
-
|
|
15
|
+
这也意味着 Basic 不是“随手工具箱”。一个能力只有在满足以下条件时,才适合进入这个模块:
|
|
31
16
|
|
|
32
|
-
|
|
17
|
+
- 它表达的是稳定、清楚、可复用的值级问题域。
|
|
18
|
+
- 它对调用方前提的假设足够少,能在不同项目中长期成立。
|
|
19
|
+
- 它适合通过清楚的输入输出语义被组合,而不是依赖隐式上下文或宿主副作用。
|
|
33
20
|
|
|
34
|
-
|
|
21
|
+
## For Using
|
|
35
22
|
|
|
36
|
-
|
|
23
|
+
当你需要把分散在业务代码中的基础判断、值转换、容器处理和轻量流程控制整理成稳定能力时,可以使用这个模块。它适合放在业务逻辑与语言原生能力之间,作为一层更可复用、也更可测试的基础模型层。
|
|
37
24
|
|
|
38
|
-
|
|
25
|
+
当前公共能力大致可以按以下几类理解:
|
|
39
26
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* const example1 = isString("hello")
|
|
48
|
-
* // Expect: false
|
|
49
|
-
* const example2 = isString(123)
|
|
50
|
-
* ```
|
|
51
|
-
*
|
|
52
|
-
* @see {@link https://……}
|
|
53
|
-
*/
|
|
54
|
-
export const isString = (value: unknown): value is string => {
|
|
55
|
-
...
|
|
56
|
-
}
|
|
57
|
-
```
|
|
27
|
+
- 值判断与基础守卫:例如 primitive、对象、数组、空值、数字特征等运行时判断,用于减少重复的分支代码。
|
|
28
|
+
- 基础值处理:例如字符串、数字、布尔值、BigInt、符号等常见值类型的转换、裁剪、计算与格式化。
|
|
29
|
+
- 容器处理:例如数组与对象的筛选、映射、分区、裁剪、合并、字段选择与标准化,适合在进入业务模型前先整理数据形态。
|
|
30
|
+
- 函数与流程控制:例如一次性调用、防抖、节流、组合、管道、记忆化、条件执行等轻量控制能力。
|
|
31
|
+
- 异步与流处理:例如 Promise 队列、重试、轮询、失败结果表达,以及围绕 `ReadableStream` 的基础消费与转换。
|
|
32
|
+
- 时间、错误与正则辅助:例如时间格式化、异常字符串化、常见模式判断等值级辅助能力。
|
|
33
|
+
- 显式增强能力:如果某个能力会对内建对象做增强,它必须保持显式调用、行为可审查,并且不应成为其它公共能力成立的隐含前提。
|
|
58
34
|
|
|
59
|
-
|
|
60
|
-
- First line: Clear, concise description starting with a verb (Check, Get, Convert, etc.)
|
|
61
|
-
- Add a blank line after the description
|
|
62
|
-
- Use `@example` tag followed by triple backticks
|
|
63
|
-
- Include multiple cases showing different scenarios
|
|
64
|
-
- Use comment format: `// Expect: <result>`
|
|
65
|
-
- Assign example results to variables like `example1`, `example2` to keep examples readable
|
|
66
|
-
- Place `@see`(if has) after the `@example` block, separated by a blank line
|
|
67
|
-
- Prefer deterministic examples; avoid randomness or time-dependent output in docs
|
|
68
|
-
- If a function returns a non-scalar, show the expected shape or key properties
|
|
35
|
+
如果你的问题已经需要环境感知、平台能力探测、全局异常监听或更明确的领域语义,应优先考虑 Environment、Exception 或其它更贴近问题域的模块,而不是继续把能力堆进 Basic。
|
|
69
36
|
|
|
70
|
-
|
|
37
|
+
## For Contributing
|
|
71
38
|
|
|
72
|
-
|
|
39
|
+
贡献 Basic 模块时,首要任务不是补齐一个方便函数,而是确认这项能力是否真的表达了稳定的值级语义。这里应长期承载的是对运行时值的清楚建模,而不是对某个调用点临时痛点的修补。
|
|
73
40
|
|
|
74
|
-
|
|
41
|
+
在扩展时,应优先遵守以下模块边界:
|
|
75
42
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
```
|
|
43
|
+
- 只收纳围绕运行时值本身展开的判断、转换、组合、格式化与轻量流程控制。
|
|
44
|
+
- 不把环境探测、宿主监听、全局状态操纵或平台接入逻辑放入 Basic。
|
|
45
|
+
- 不为了省几行调用代码而公开一次性便捷包装;只有值得长期承诺的公共语义才应进入模块。
|
|
46
|
+
- 如果某项能力依赖显式增强内建对象,必须让增强保持可选,而不是让整个模块隐式建立在原型修改之上。
|
|
81
47
|
|
|
82
|
-
|
|
48
|
+
### JSDoc 注释格式要求
|
|
83
49
|
|
|
84
|
-
|
|
50
|
+
- 每个公开导出的目标(类型、函数、变量、类等)都应包含 JSDoc 注释,让人在不跳转实现的情况下就能理解用途。
|
|
51
|
+
- JSDoc 注释第一行应为清晰且简洁的描述,该描述优先使用中文(英文也可以)。
|
|
52
|
+
- 如果描述后还有其他内容,应在描述后加一个空行。
|
|
53
|
+
- 如果有示例,应使用 `@example` 标签,后接三重反引号代码块(不带语言标识)。
|
|
54
|
+
- 如果有示例,应包含多个场景,展示不同用法,尤其要覆盖常见组合方式或边界输入。
|
|
55
|
+
- 如果有示例,应使用注释格式说明每个场景:`// Expect: <result>`。
|
|
56
|
+
- 如果有示例,应将结果赋值给 `example1`、`example2` 之类的变量,以保持示例易读。
|
|
57
|
+
- 如果有示例,`// Expect: <result>` 应该位于 `example1`、`example2` 之前,以保持示例的逻辑清晰。
|
|
58
|
+
- 如果有示例,应优先使用确定性示例;避免断言精确的随机输出。
|
|
59
|
+
- 如果函数返回结构化字符串,应展示其预期格式特征。
|
|
60
|
+
- 如果有参考资料,应将 `@see` 放在 `@example` 代码块之后,并用一个空行分隔。
|
|
85
61
|
|
|
86
|
-
|
|
62
|
+
### 实现规范要求
|
|
87
63
|
|
|
88
|
-
|
|
64
|
+
- 不同程序元素之间使用一个空行分隔,保持结构清楚。这里的程序元素,通常指函数、类型、常量,以及直接服务于它们的辅助元素。
|
|
65
|
+
- 某程序元素独占的辅助元素与该程序元素本身视为一个整体,不要在它们之间添加空行。
|
|
66
|
+
- 程序元素的辅助元素应该放置在该程序元素的上方,以保持阅读时的逻辑顺序。
|
|
67
|
+
- 若辅助元素被多个程序元素共享,则应将其视为独立的程序元素,放在这些程序元素中第一个相关目标的上方,并与后续程序元素之间保留一个空行。
|
|
68
|
+
- 辅助元素也应该像其它程序元素一样,保持清晰的命名和适当的注释,以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
|
|
69
|
+
- 辅助元素的命名必须以前缀 `internal` 开头(或 `Internal`,大小写不敏感)。
|
|
70
|
+
- 辅助元素永远不要公开导出。
|
|
71
|
+
- 被模块内多个不同文件中的程序元素共享的辅助元素,应该放在一个单独的文件中,例如 `./src/basic/internal.ts`;若当前没有必要,不必为了形式强行拆分。
|
|
72
|
+
- 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时,才应将其视为子模块。
|
|
73
|
+
- 子模块包含多个文件时,应该为其单独创建子文件夹,并为其创建单独的 Barrel 文件;父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
|
|
74
|
+
- 子模块不需要有自己的 `README.md`。
|
|
75
|
+
- 子模块可以有自己的 `internal.ts` 文件,多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中,单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
|
|
76
|
+
- 对模块依赖关系的要求(通常是不循环依赖或不反向依赖)与对 DRY 的要求可能产生冲突。此时,若复用的代码数量不大,可以适当牺牲 DRY,复制粘贴并保留必要的注释说明;若复用的代码数量较大,则可以将其抽象到新的文件或子模块中,如 `common.ts`,并在需要的地方导入使用。
|
|
77
|
+
- Basic 的实现应优先保证输入输出语义直接、低副作用、可组合,而不是追求隐式魔法或宿主绑定行为。
|
|
89
78
|
|
|
90
|
-
|
|
79
|
+
### 导出策略要求
|
|
91
80
|
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
81
|
+
- 保持内部辅助项和内部符号为私有,不要让外部接入依赖临时性的内部结构。
|
|
82
|
+
- 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
|
|
83
|
+
- Barrel 文件应命名为 `index.ts`,放在模块目录根部,并且所有公共 API 都应从该文件导出。
|
|
84
|
+
- 新增公共能力时,应优先检查它是否表达稳定、清楚且值得长期维护的值级语义,而不是某段实现细节的便捷暴露;仅在确认需要长期对外承诺时再加入 Barrel 导出。
|
|
96
85
|
|
|
97
|
-
|
|
86
|
+
### 测试要求
|
|
98
87
|
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
**Format:** `<domain><Operation><Qualifier>`
|
|
108
|
-
|
|
109
|
-
- `is*` for predicates and checks (for example, `isPlainObject`, `isFiniteNumber`)
|
|
110
|
-
- `string*` for string utilities (`stringRandom`, `stringTruncate`)
|
|
111
|
-
- `number*` for number utilities (`numberClamp`, `numberInRange`)
|
|
112
|
-
- `boolean*`, `date*`, `regexp*`, `error*`, `symbol*`, `bigint*` for other domains
|
|
113
|
-
|
|
114
|
-
#### 3.2 Common Verb Prefixes
|
|
115
|
-
|
|
116
|
-
- `is*` - Returns boolean for validation
|
|
117
|
-
- `has*` - Returns boolean for existence checks
|
|
118
|
-
- `get*` / `extract*` - Returns a value
|
|
119
|
-
- `to*` - Conversion operations
|
|
120
|
-
|
|
121
|
-
### 4. Export Strategy
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
// Always export public functions
|
|
125
|
-
export const publicFunction = () => {}
|
|
126
|
-
|
|
127
|
-
// Never export internal helpers
|
|
128
|
-
const internalHelper = () => {}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Keep domain exports in their files and re-export them via the barrel in `index.ts`.
|
|
132
|
-
|
|
133
|
-
### 5. Common Pitfalls to Avoid
|
|
134
|
-
|
|
135
|
-
1. Do not rely on `typeof` alone for objects (for example, `typeof null === "object"`).
|
|
136
|
-
2. Do not confuse `NaN` with numbers that cannot be parsed.
|
|
137
|
-
3. Do not treat boxed objects (`new String("x")`) as primitives without checks.
|
|
138
|
-
4. Do not mutate inputs unless the function name and docs make it explicit.
|
|
139
|
-
5. Do not introduce locale-dependent behavior without documenting it.
|
|
140
|
-
|
|
141
|
-
### 6. Testing Requirements
|
|
142
|
-
|
|
143
|
-
- Write one test per function.
|
|
144
|
-
- If multiple cases are needed, include them within the same test.
|
|
88
|
+
- 若程序元素是函数,则只为该函数编写一个测试,如果该函数需要测试多个用例,应放在同一个测试中。
|
|
89
|
+
- 若程序元素是类,则至少要为该类的每一个方法编写一个测试,如果该方法需要测试多个用例,应放在同一个测试中。
|
|
90
|
+
- 若程序元素是类,除了为该类的每一个方法编写至少一个测试之外,还可以为该类编写任意多个测试,以覆盖该类的不同使用场景或边界情况。
|
|
91
|
+
- 若编写测试时需要用到辅助元素(Mock 或 Spy 等),可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单,则可以直接放在每一个测试内部,优先保证每个测试的独立性,而不是追求极致 DRY;若辅助元素较为复杂或需要在多个测试中复用,则可以放在测试文件顶部,供该测试文件中的所有测试使用。
|
|
92
|
+
- 测试顺序应与源文件中被测试目标的原始顺序保持一致。
|
|
93
|
+
- 若该模块不需要测试,必须在说明文件中明确说明该模块不需要测试,并说明理由。一般来说,只有在该模块没有可执行的公共函数、只承载类型层表达,或其语义已被上层模块的测试完整覆盖且重复测试几乎不再带来额外价值时,才适合这样处理。
|
|
94
|
+
- 模块的单元测试文件目录是 `./tests/unit/basic`,若模块包含子模块,则子模块的单元测试文件目录为 `./tests/unit/basic/<sub-module-name>`。
|
|
95
|
+
- 对带有时间、随机、异步调度或流消费语义的能力,应显式控制前提,避免把不稳定行为写成稳定断言。
|
package/src/basic/function.ts
CHANGED
|
@@ -26,23 +26,28 @@ export const functionIife = <T extends AnyFunction>(
|
|
|
26
26
|
return fn(...args)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* 表示只会保留首次执行结果的一次性函数。
|
|
31
|
+
*/
|
|
29
32
|
export type FunctionOnce<T extends AnyFunction> =
|
|
30
33
|
(...args: Parameters<T>) => ReturnType<T>
|
|
31
34
|
/**
|
|
32
|
-
*
|
|
35
|
+
* 生成一个只在首次调用时真正执行的函数。
|
|
33
36
|
*
|
|
34
37
|
* @example
|
|
35
38
|
* ```
|
|
36
|
-
* const
|
|
37
|
-
* //
|
|
38
|
-
* const
|
|
39
|
-
* //
|
|
40
|
-
* const
|
|
41
|
-
*
|
|
39
|
+
* const exampleFn1 = functionOnce((x: number) => x * 2)
|
|
40
|
+
* // Expect: 10
|
|
41
|
+
* const example1 = exampleFn1(5)
|
|
42
|
+
* // Expect: 10
|
|
43
|
+
* const example2 = exampleFn1(10)
|
|
44
|
+
*
|
|
42
45
|
* let callCount = 0
|
|
43
|
-
* const
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
+
* const exampleFn2 = functionOnce((x: number) => x * 2, (times) => { callCount = times })
|
|
47
|
+
* exampleFn2(5)
|
|
48
|
+
* exampleFn2(10)
|
|
49
|
+
* // Expect: 2
|
|
50
|
+
* const example3 = callCount
|
|
46
51
|
* ```
|
|
47
52
|
*/
|
|
48
53
|
export const functionOnce = <T extends AnyFunction>(
|
|
@@ -67,20 +72,23 @@ export const functionOnce = <T extends AnyFunction>(
|
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
/**
|
|
76
|
+
* 表示简单防抖后的函数类型。
|
|
77
|
+
*/
|
|
70
78
|
export type FunctionDebouncedSimple<T extends AnyFunction> =
|
|
71
79
|
(...args: Parameters<T>) => void
|
|
80
|
+
|
|
72
81
|
/**
|
|
73
|
-
*
|
|
74
|
-
* the original function until after a specified wait time
|
|
75
|
-
* has elapsed since the last time the debounced function was called.
|
|
82
|
+
* 生成一个简单防抖函数,在最后一次调用后的指定时间再触发原函数。
|
|
76
83
|
*
|
|
77
84
|
* @example
|
|
78
85
|
* ```
|
|
79
|
-
* const
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
86
|
+
* const records: number[] = []
|
|
87
|
+
* const exampleFn1 = functionDebounceSimple((x: number) => { records.push(x) }, 10)
|
|
88
|
+
* exampleFn1(5)
|
|
89
|
+
* exampleFn1(10)
|
|
90
|
+
* // Expect: records.length === 0
|
|
91
|
+
* const example1 = records.length === 0
|
|
84
92
|
* ```
|
|
85
93
|
*/
|
|
86
94
|
export const functionDebounceSimple = <T extends AnyFunction>(
|
|
@@ -96,22 +104,23 @@ export const functionDebounceSimple = <T extends AnyFunction>(
|
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
|
|
107
|
+
/**
|
|
108
|
+
* 表示返回 `Promise` 的防抖函数类型。
|
|
109
|
+
*/
|
|
99
110
|
export type FunctionDebounced<T extends AnyFunction>
|
|
100
111
|
= (...args: Parameters<T>) => Promise<ReturnType<T>>
|
|
101
112
|
/**
|
|
102
|
-
*
|
|
103
|
-
* to the result of the original function. If the debounced function is called
|
|
104
|
-
* multiple times within the debounce period, it will only execute the original
|
|
105
|
-
* function once, and all calls will receive the same result.
|
|
113
|
+
* 生成一个返回 `Promise` 的防抖函数,并在防抖窗口内合并并发调用。
|
|
106
114
|
*
|
|
107
115
|
* @example
|
|
108
116
|
* ```
|
|
109
|
-
* const
|
|
110
|
-
*
|
|
111
|
-
* const
|
|
112
|
-
* //
|
|
113
|
-
* const
|
|
114
|
-
* //
|
|
117
|
+
* const exampleFn1 = debounce(async (x: number) => x * 2, 10)
|
|
118
|
+
* const example1 = exampleFn1(5)
|
|
119
|
+
* const example2 = exampleFn1(10)
|
|
120
|
+
* // Expect: example1 instanceof Promise
|
|
121
|
+
* const example3 = example1 instanceof Promise
|
|
122
|
+
* // Expect: example2 instanceof Promise
|
|
123
|
+
* const example4 = example2 instanceof Promise
|
|
115
124
|
* ```
|
|
116
125
|
*/
|
|
117
126
|
export const debounce = <T extends AnyFunction>(
|
|
@@ -139,25 +148,23 @@ export const debounce = <T extends AnyFunction>(
|
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
const THROTTLE_TYPE_ERROR = new TypeError("Throttle: fn must be a SyncFunction or AsyncFunction")
|
|
151
|
+
/**
|
|
152
|
+
* 表示基于时间窗口的简单节流函数类型。
|
|
153
|
+
*/
|
|
142
154
|
export type FunctionThrottleTimeSimple<T extends AnyFunction> =
|
|
143
155
|
(...args: Parameters<T>) => void
|
|
144
156
|
/**
|
|
145
|
-
*
|
|
146
|
-
* once per every specified milliseconds. The throttled function will execute the original
|
|
147
|
-
* function immediately on the first call, and then ignore subsequent calls until the
|
|
148
|
-
* specified time has elapsed.
|
|
157
|
+
* 生成一个简单时间节流函数,在指定时间窗口内最多执行一次原函数。
|
|
149
158
|
*
|
|
150
|
-
*
|
|
151
|
-
* during which the original function can be invoked is greater than the sum of the
|
|
152
|
-
* specified milliseconds and the execution time of the original function.
|
|
159
|
+
* 当 `strict` 为 `true` 时,节流窗口会同时考虑等待时长与目标函数执行时长。
|
|
153
160
|
*
|
|
154
161
|
* @example
|
|
155
162
|
* ```
|
|
156
163
|
* let called = 0
|
|
157
|
-
* const
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* // Expect:
|
|
164
|
+
* const exampleFn1 = functionThrottleTimeSimple(() => { called += 1 }, 100)
|
|
165
|
+
* exampleFn1()
|
|
166
|
+
* exampleFn1()
|
|
167
|
+
* // Expect: 1
|
|
161
168
|
* const example1 = called
|
|
162
169
|
* ```
|
|
163
170
|
*/
|
|
@@ -212,19 +219,21 @@ export const functionThrottleTimeSimple = <T extends AnyFunction>(
|
|
|
212
219
|
}
|
|
213
220
|
}
|
|
214
221
|
|
|
222
|
+
/**
|
|
223
|
+
* 表示执行期间丢弃重复调用的简单节流函数类型。
|
|
224
|
+
*/
|
|
215
225
|
export type FunctionThrottleSimple<T extends AnyFunction> =
|
|
216
226
|
(...args: Parameters<T>) => void
|
|
217
227
|
/**
|
|
218
|
-
*
|
|
219
|
-
* when it is not currently executing.
|
|
228
|
+
* 生成一个在执行期间忽略重复调用的节流函数。
|
|
220
229
|
*
|
|
221
230
|
* @example
|
|
222
231
|
* ```
|
|
223
232
|
* let called = 0
|
|
224
|
-
* const
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* // Expect:
|
|
233
|
+
* const exampleFn1 = functionThrottleSimple(() => { called += 1 })
|
|
234
|
+
* exampleFn1()
|
|
235
|
+
* exampleFn1()
|
|
236
|
+
* // Expect: 1
|
|
228
237
|
* const example1 = called
|
|
229
238
|
* ```
|
|
230
239
|
*/
|
|
@@ -256,23 +265,25 @@ export const functionThrottleSimple = <T extends AnyFunction>(
|
|
|
256
265
|
}
|
|
257
266
|
}
|
|
258
267
|
|
|
268
|
+
/**
|
|
269
|
+
* 表示返回 `Promise` 的时间节流函数类型。
|
|
270
|
+
*/
|
|
259
271
|
export type FunctionThrottleTime<T extends AnyFunction> =
|
|
260
272
|
(...args: Parameters<T>) => Promise<ReturnType<T>>
|
|
261
273
|
/**
|
|
262
|
-
*
|
|
263
|
-
* of the original function. The throttled function will ensure that the original
|
|
264
|
-
* function is invoked at most once per every specified milliseconds.
|
|
274
|
+
* 生成一个返回 `Promise` 的时间节流函数。
|
|
265
275
|
*
|
|
266
|
-
*
|
|
267
|
-
* can be invoked will be greater than the sum of the specified milliseconds and
|
|
268
|
-
* the execution time of the original function.
|
|
276
|
+
* 当 `strict` 为 `true` 时,节流窗口会同时考虑等待时长与目标函数执行时长。
|
|
269
277
|
*
|
|
270
278
|
* @example
|
|
271
279
|
* ```
|
|
272
|
-
* const
|
|
273
|
-
* const
|
|
274
|
-
* const
|
|
275
|
-
* // Expect:
|
|
280
|
+
* const exampleFn1 = throttleTime(async (value: number) => value * 2, 100)
|
|
281
|
+
* const example1 = exampleFn1(2)
|
|
282
|
+
* const example2 = exampleFn1(3)
|
|
283
|
+
* // Expect: example1 instanceof Promise
|
|
284
|
+
* const example3 = example1 instanceof Promise
|
|
285
|
+
* // Expect: example2 instanceof Promise
|
|
286
|
+
* const example4 = example2 instanceof Promise
|
|
276
287
|
* ```
|
|
277
288
|
*/
|
|
278
289
|
export const throttleTime = <T extends AnyFunction>(
|
|
@@ -323,18 +334,23 @@ export const throttleTime = <T extends AnyFunction>(
|
|
|
323
334
|
}
|
|
324
335
|
}
|
|
325
336
|
|
|
337
|
+
/**
|
|
338
|
+
* 表示合并并发调用的节流函数类型。
|
|
339
|
+
*/
|
|
326
340
|
export type FunctionThrottle<T extends AnyFunction> =
|
|
327
341
|
(...args: Parameters<T>) => Promise<ReturnType<T>>
|
|
328
342
|
/**
|
|
329
|
-
*
|
|
330
|
-
* of the original function and coalesces concurrent calls.
|
|
343
|
+
* 生成一个返回 `Promise` 的节流函数,并合并并发调用。
|
|
331
344
|
*
|
|
332
345
|
* @example
|
|
333
346
|
* ```
|
|
334
|
-
* const
|
|
335
|
-
* const
|
|
336
|
-
* const
|
|
337
|
-
* // Expect:
|
|
347
|
+
* const exampleFn1 = functionThrottle(async () => "ok")
|
|
348
|
+
* const example1 = exampleFn1()
|
|
349
|
+
* const example2 = exampleFn1()
|
|
350
|
+
* // Expect: example1 instanceof Promise
|
|
351
|
+
* const example3 = example1 instanceof Promise
|
|
352
|
+
* // Expect: example2 instanceof Promise
|
|
353
|
+
* const example4 = example2 instanceof Promise
|
|
338
354
|
* ```
|
|
339
355
|
*/
|
|
340
356
|
export const functionThrottle = <T extends AnyFunction>(
|
|
@@ -409,6 +425,9 @@ export const functionPipe = <Fns extends AnyFunction[]>(
|
|
|
409
425
|
return functionCompose(...fns.toReversed()) as FunctionPipeAll<Fns>
|
|
410
426
|
}
|
|
411
427
|
|
|
428
|
+
/**
|
|
429
|
+
* 表示带参数缓存能力的记忆化函数类型。
|
|
430
|
+
*/
|
|
412
431
|
export type FunctionMemorized<T extends AnyFunction> =
|
|
413
432
|
(...args: Parameters<T>) => ReturnType<T>
|
|
414
433
|
// oxlint-disable-next-line no-explicit-any
|
|
@@ -434,7 +453,7 @@ const defaultMemorizeHasher = (...args: any[]): string => JSON.stringify(args)
|
|
|
434
453
|
*/
|
|
435
454
|
export const functionMemorize = <T extends AnyFunction>(
|
|
436
455
|
fn: T,
|
|
437
|
-
hashFunction?: (...args: Parameters<T>) => unknown
|
|
456
|
+
hashFunction?: (...args: Parameters<T>) => unknown | undefined
|
|
438
457
|
): FunctionMemorized<T> => {
|
|
439
458
|
const cache = new Map()
|
|
440
459
|
const hasher = hashFunction ?? defaultMemorizeHasher
|