@yunzai-ng/core 0.1.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/LICENSE +661 -0
- package/README.md +51 -0
- package/dist/adapter/accounts.d.ts +174 -0
- package/dist/adapter/accounts.d.ts.map +1 -0
- package/dist/adapter/accounts.js +653 -0
- package/dist/adapter/accounts.js.map +1 -0
- package/dist/adapter/bots.d.ts +142 -0
- package/dist/adapter/bots.d.ts.map +1 -0
- package/dist/adapter/bots.js +454 -0
- package/dist/adapter/bots.js.map +1 -0
- package/dist/adapter/host.d.ts +114 -0
- package/dist/adapter/host.d.ts.map +1 -0
- package/dist/adapter/host.js +90 -0
- package/dist/adapter/host.js.map +1 -0
- package/dist/adapter/login.d.ts +174 -0
- package/dist/adapter/login.d.ts.map +1 -0
- package/dist/adapter/login.js +345 -0
- package/dist/adapter/login.js.map +1 -0
- package/dist/adapter/registry.d.ts +102 -0
- package/dist/adapter/registry.d.ts.map +1 -0
- package/dist/adapter/registry.js +150 -0
- package/dist/adapter/registry.js.map +1 -0
- package/dist/config/core-config.d.ts +151 -0
- package/dist/config/core-config.d.ts.map +1 -0
- package/dist/config/core-config.js +338 -0
- package/dist/config/core-config.js.map +1 -0
- package/dist/config/schema.d.ts +449 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +871 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/store.d.ts +184 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +428 -0
- package/dist/config/store.js.map +1 -0
- package/dist/config/yaml.d.ts +23 -0
- package/dist/config/yaml.d.ts.map +1 -0
- package/dist/config/yaml.js +108 -0
- package/dist/config/yaml.js.map +1 -0
- package/dist/http/client.d.ts +82 -0
- package/dist/http/client.d.ts.map +1 -0
- package/dist/http/client.js +658 -0
- package/dist/http/client.js.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/app.d.ts +244 -0
- package/dist/kernel/app.d.ts.map +1 -0
- package/dist/kernel/app.js +654 -0
- package/dist/kernel/app.js.map +1 -0
- package/dist/kernel/kv-sink.d.ts +34 -0
- package/dist/kernel/kv-sink.d.ts.map +1 -0
- package/dist/kernel/kv-sink.js +25 -0
- package/dist/kernel/kv-sink.js.map +1 -0
- package/dist/kernel/policy.d.ts +77 -0
- package/dist/kernel/policy.d.ts.map +1 -0
- package/dist/kernel/policy.js +99 -0
- package/dist/kernel/policy.js.map +1 -0
- package/dist/kernel/runtime.d.ts +117 -0
- package/dist/kernel/runtime.d.ts.map +1 -0
- package/dist/kernel/runtime.js +197 -0
- package/dist/kernel/runtime.js.map +1 -0
- package/dist/kernel/sql-sink.d.ts +36 -0
- package/dist/kernel/sql-sink.d.ts.map +1 -0
- package/dist/kernel/sql-sink.js +114 -0
- package/dist/kernel/sql-sink.js.map +1 -0
- package/dist/logger/format.d.ts +67 -0
- package/dist/logger/format.d.ts.map +1 -0
- package/dist/logger/format.js +218 -0
- package/dist/logger/format.js.map +1 -0
- package/dist/logger/index.d.ts +97 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +363 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/rotate.d.ts +47 -0
- package/dist/logger/rotate.d.ts.map +1 -0
- package/dist/logger/rotate.js +242 -0
- package/dist/logger/rotate.js.map +1 -0
- package/dist/message/segment.d.ts +255 -0
- package/dist/message/segment.d.ts.map +1 -0
- package/dist/message/segment.js +510 -0
- package/dist/message/segment.js.map +1 -0
- package/dist/message/split.d.ts +34 -0
- package/dist/message/split.d.ts.map +1 -0
- package/dist/message/split.js +79 -0
- package/dist/message/split.js.map +1 -0
- package/dist/message/target.d.ts +29 -0
- package/dist/message/target.d.ts.map +1 -0
- package/dist/message/target.js +34 -0
- package/dist/message/target.js.map +1 -0
- package/dist/pipeline/cooldown.d.ts +84 -0
- package/dist/pipeline/cooldown.d.ts.map +1 -0
- package/dist/pipeline/cooldown.js +94 -0
- package/dist/pipeline/cooldown.js.map +1 -0
- package/dist/pipeline/dispatch.d.ts +98 -0
- package/dist/pipeline/dispatch.d.ts.map +1 -0
- package/dist/pipeline/dispatch.js +323 -0
- package/dist/pipeline/dispatch.js.map +1 -0
- package/dist/pipeline/event.d.ts +130 -0
- package/dist/pipeline/event.d.ts.map +1 -0
- package/dist/pipeline/event.js +538 -0
- package/dist/pipeline/event.js.map +1 -0
- package/dist/pipeline/middleware.d.ts +63 -0
- package/dist/pipeline/middleware.d.ts.map +1 -0
- package/dist/pipeline/middleware.js +174 -0
- package/dist/pipeline/middleware.js.map +1 -0
- package/dist/pipeline/prompt.d.ts +80 -0
- package/dist/pipeline/prompt.d.ts.map +1 -0
- package/dist/pipeline/prompt.js +155 -0
- package/dist/pipeline/prompt.js.map +1 -0
- package/dist/pipeline/router.d.ts +98 -0
- package/dist/pipeline/router.d.ts.map +1 -0
- package/dist/pipeline/router.js +489 -0
- package/dist/pipeline/router.js.map +1 -0
- package/dist/platform/detect.d.ts +24 -0
- package/dist/platform/detect.d.ts.map +1 -0
- package/dist/platform/detect.js +178 -0
- package/dist/platform/detect.js.map +1 -0
- package/dist/platform/paths.d.ts +38 -0
- package/dist/platform/paths.d.ts.map +1 -0
- package/dist/platform/paths.js +129 -0
- package/dist/platform/paths.js.map +1 -0
- package/dist/platform/system.d.ts +71 -0
- package/dist/platform/system.d.ts.map +1 -0
- package/dist/platform/system.js +242 -0
- package/dist/platform/system.js.map +1 -0
- package/dist/plugin/context.d.ts +92 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +573 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/define.d.ts +92 -0
- package/dist/plugin/define.d.ts.map +1 -0
- package/dist/plugin/define.js +82 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/discover.d.ts +106 -0
- package/dist/plugin/discover.d.ts.map +1 -0
- package/dist/plugin/discover.js +254 -0
- package/dist/plugin/discover.js.map +1 -0
- package/dist/plugin/events.d.ts +109 -0
- package/dist/plugin/events.d.ts.map +1 -0
- package/dist/plugin/events.js +209 -0
- package/dist/plugin/events.js.map +1 -0
- package/dist/plugin/hooks.d.ts +266 -0
- package/dist/plugin/hooks.d.ts.map +1 -0
- package/dist/plugin/hooks.js +84 -0
- package/dist/plugin/hooks.js.map +1 -0
- package/dist/plugin/host.d.ts +160 -0
- package/dist/plugin/host.d.ts.map +1 -0
- package/dist/plugin/host.js +546 -0
- package/dist/plugin/host.js.map +1 -0
- package/dist/plugin/market.d.ts +264 -0
- package/dist/plugin/market.d.ts.map +1 -0
- package/dist/plugin/market.js +700 -0
- package/dist/plugin/market.js.map +1 -0
- package/dist/plugin/services.d.ts +116 -0
- package/dist/plugin/services.d.ts.map +1 -0
- package/dist/plugin/services.js +213 -0
- package/dist/plugin/services.js.map +1 -0
- package/dist/plugin/tar.d.ts +65 -0
- package/dist/plugin/tar.d.ts.map +1 -0
- package/dist/plugin/tar.js +277 -0
- package/dist/plugin/tar.js.map +1 -0
- package/dist/render/registry.d.ts +127 -0
- package/dist/render/registry.d.ts.map +1 -0
- package/dist/render/registry.js +306 -0
- package/dist/render/registry.js.map +1 -0
- package/dist/scheduler/index.d.ts +67 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +279 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/server/api.d.ts +179 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +602 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/auth.d.ts +83 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +178 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/browse.d.ts +60 -0
- package/dist/server/browse.d.ts.map +1 -0
- package/dist/server/browse.js +187 -0
- package/dist/server/browse.js.map +1 -0
- package/dist/server/files.d.ts +27 -0
- package/dist/server/files.d.ts.map +1 -0
- package/dist/server/files.js +76 -0
- package/dist/server/files.js.map +1 -0
- package/dist/server/index.d.ts +189 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1123 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/table.d.ts +105 -0
- package/dist/server/table.d.ts.map +1 -0
- package/dist/server/table.js +289 -0
- package/dist/server/table.js.map +1 -0
- package/dist/store/index.d.ts +50 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +120 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/json.d.ts +73 -0
- package/dist/store/json.d.ts.map +1 -0
- package/dist/store/json.js +174 -0
- package/dist/store/json.js.map +1 -0
- package/dist/store/kv.d.ts +126 -0
- package/dist/store/kv.d.ts.map +1 -0
- package/dist/store/kv.js +232 -0
- package/dist/store/kv.js.map +1 -0
- package/dist/store/level.d.ts +103 -0
- package/dist/store/level.d.ts.map +1 -0
- package/dist/store/level.js +119 -0
- package/dist/store/level.js.map +1 -0
- package/dist/store/memory.d.ts +61 -0
- package/dist/store/memory.d.ts.map +1 -0
- package/dist/store/memory.js +94 -0
- package/dist/store/memory.js.map +1 -0
- package/dist/store/sql.d.ts +142 -0
- package/dist/store/sql.d.ts.map +1 -0
- package/dist/store/sql.js +246 -0
- package/dist/store/sql.js.map +1 -0
- package/dist/testing/fake.d.ts +109 -0
- package/dist/testing/fake.d.ts.map +1 -0
- package/dist/testing/fake.js +196 -0
- package/dist/testing/fake.js.map +1 -0
- package/dist/testing/index.d.ts +16 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +16 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-adapter.d.ts +205 -0
- package/dist/testing/mock-adapter.d.ts.map +1 -0
- package/dist/testing/mock-adapter.js +309 -0
- package/dist/testing/mock-adapter.js.map +1 -0
- package/dist/util/deep.d.ts +108 -0
- package/dist/util/deep.d.ts.map +1 -0
- package/dist/util/deep.js +275 -0
- package/dist/util/deep.js.map +1 -0
- package/dist/util/defer.d.ts +107 -0
- package/dist/util/defer.d.ts.map +1 -0
- package/dist/util/defer.js +163 -0
- package/dist/util/defer.js.map +1 -0
- package/dist/util/dispose.d.ts +88 -0
- package/dist/util/dispose.d.ts.map +1 -0
- package/dist/util/dispose.js +143 -0
- package/dist/util/dispose.js.map +1 -0
- package/dist/util/duration.d.ts +28 -0
- package/dist/util/duration.d.ts.map +1 -0
- package/dist/util/duration.js +77 -0
- package/dist/util/duration.js.map +1 -0
- package/dist/util/fs.d.ts +110 -0
- package/dist/util/fs.d.ts.map +1 -0
- package/dist/util/fs.js +269 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/id.d.ts +49 -0
- package/dist/util/id.d.ts.map +1 -0
- package/dist/util/id.js +87 -0
- package/dist/util/id.js.map +1 -0
- package/dist/util/lru.d.ts +74 -0
- package/dist/util/lru.d.ts.map +1 -0
- package/dist/util/lru.js +156 -0
- package/dist/util/lru.js.map +1 -0
- package/dist/util/queue.d.ts +64 -0
- package/dist/util/queue.d.ts.map +1 -0
- package/dist/util/queue.js +147 -0
- package/dist/util/queue.js.map +1 -0
- package/dist/util/text.d.ts +86 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +182 -0
- package/dist/util/text.js.map +1 -0
- package/package.json +44 -0
- package/src/adapter/accounts.ts +758 -0
- package/src/adapter/bots.ts +582 -0
- package/src/adapter/host.ts +224 -0
- package/src/adapter/login.ts +481 -0
- package/src/adapter/registry.ts +202 -0
- package/src/config/core-config.test.ts +60 -0
- package/src/config/core-config.ts +401 -0
- package/src/config/schema.test.ts +179 -0
- package/src/config/schema.ts +1036 -0
- package/src/config/store.test.ts +245 -0
- package/src/config/store.ts +506 -0
- package/src/config/yaml.ts +119 -0
- package/src/http/client.test.ts +568 -0
- package/src/http/client.ts +777 -0
- package/src/index.ts +106 -0
- package/src/kernel/app.test.ts +267 -0
- package/src/kernel/app.ts +843 -0
- package/src/kernel/kv-sink.ts +58 -0
- package/src/kernel/policy.ts +120 -0
- package/src/kernel/runtime.test.ts +542 -0
- package/src/kernel/runtime.ts +307 -0
- package/src/kernel/sql-sink.ts +154 -0
- package/src/logger/format.ts +259 -0
- package/src/logger/index.ts +427 -0
- package/src/logger/rotate.ts +265 -0
- package/src/message/segment.test.ts +335 -0
- package/src/message/segment.ts +569 -0
- package/src/message/split.ts +97 -0
- package/src/message/target.ts +48 -0
- package/src/pipeline/cooldown.ts +136 -0
- package/src/pipeline/dispatch.ts +419 -0
- package/src/pipeline/event.ts +735 -0
- package/src/pipeline/middleware.test.ts +426 -0
- package/src/pipeline/middleware.ts +199 -0
- package/src/pipeline/prompt.ts +212 -0
- package/src/pipeline/router.test.ts +432 -0
- package/src/pipeline/router.ts +575 -0
- package/src/platform/detect.ts +178 -0
- package/src/platform/paths.ts +147 -0
- package/src/platform/system.test.ts +102 -0
- package/src/platform/system.ts +289 -0
- package/src/plugin/context.test.ts +459 -0
- package/src/plugin/context.ts +757 -0
- package/src/plugin/define.test.ts +120 -0
- package/src/plugin/define.ts +142 -0
- package/src/plugin/discover.test.ts +253 -0
- package/src/plugin/discover.ts +353 -0
- package/src/plugin/events.test.ts +162 -0
- package/src/plugin/events.ts +266 -0
- package/src/plugin/hooks.ts +373 -0
- package/src/plugin/host.test.ts +696 -0
- package/src/plugin/host.ts +738 -0
- package/src/plugin/market.test.ts +781 -0
- package/src/plugin/market.ts +870 -0
- package/src/plugin/services.test.ts +135 -0
- package/src/plugin/services.ts +261 -0
- package/src/plugin/tar.test.ts +158 -0
- package/src/plugin/tar.ts +309 -0
- package/src/render/registry.test.ts +127 -0
- package/src/render/registry.ts +439 -0
- package/src/scheduler/index.ts +357 -0
- package/src/server/api.test.ts +802 -0
- package/src/server/api.ts +869 -0
- package/src/server/auth.ts +201 -0
- package/src/server/browse.test.ts +193 -0
- package/src/server/browse.ts +240 -0
- package/src/server/files.ts +97 -0
- package/src/server/index.test.ts +566 -0
- package/src/server/index.ts +1386 -0
- package/src/server/table.ts +351 -0
- package/src/store/index.ts +156 -0
- package/src/store/json.ts +198 -0
- package/src/store/kv.test.ts +307 -0
- package/src/store/kv.ts +256 -0
- package/src/store/level.ts +167 -0
- package/src/store/memory.ts +109 -0
- package/src/store/sql.test.ts +204 -0
- package/src/store/sql.ts +324 -0
- package/src/testing/fake.ts +297 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/mock-adapter.ts +588 -0
- package/src/util/deep.ts +272 -0
- package/src/util/defer.ts +211 -0
- package/src/util/dispose.ts +169 -0
- package/src/util/duration.ts +82 -0
- package/src/util/fs.ts +279 -0
- package/src/util/id.ts +94 -0
- package/src/util/lru.ts +185 -0
- package/src/util/queue.ts +167 -0
- package/src/util/text.ts +189 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模块职责:内存 Mock 适配器 —— 不连接任何平台,在进程内直接收发消息
|
|
3
|
+
* 依赖方向:只依赖 `@yunzai-ng/types` 与 message/segment;不依赖内核其余任何模块,
|
|
4
|
+
* 因此任何一层的测试均可引用它,不会反向将被测模块引入
|
|
5
|
+
* 生命周期:一次 `createMockAdapter()` 对应一个测试用例;驱动实例由内核在连接账号时创建
|
|
6
|
+
* 注意事项:三项设计取舍,使用前应先阅读:
|
|
7
|
+
*
|
|
8
|
+
* 1) **这是真实实现,而非 `vi.fn()` 拼装出的替身对象**。它在编译期即必须满足
|
|
9
|
+
* `AdapterProvider` / `BotDriver`,因而同时是测试替身与"编写一个新适配器
|
|
10
|
+
* 至少需实现哪些方法"的可执行文档 —— 编写 adapter-napcat 时可直接参照。
|
|
11
|
+
* 以 `as unknown as BotDriver` 强制转换得到的替身对象无法做到这一点:接口新增成员后,
|
|
12
|
+
* 测试仍能编译通过,直至真实适配器上线方发现存在未实现的方法。
|
|
13
|
+
*
|
|
14
|
+
* 2) **投递是单向的,断言必须等待回调**。`host.submit()` 同步返回,内核内部
|
|
15
|
+
* 异步处理(见 kernel/runtime.ts 第 3 步的 `dispatch` 未 await),因此
|
|
16
|
+
* `await receiveGroup(...)` 无法等到回复,需等待时应使用 `waitForSend()`。
|
|
17
|
+
*
|
|
18
|
+
* 3) **`waitForSend()` 超时会将已发出的内容写入错误信息**。否则 vitest
|
|
19
|
+
* 仅报告一句 "test timed out",无从区分是命令未匹配、插件抛出错误、
|
|
20
|
+
* 还是回复内容不符 —— 这三种情形的排查方向完全不同。
|
|
21
|
+
*/
|
|
22
|
+
import type { AdapterHost, AdapterProvider, BotCapability, BotDriver, ForwardNode, GroupRole, IncomingEvent, IncomingMessageEvent, MessageContent, Segment, SendOptions, SendTarget } from "@yunzai-ng/types";
|
|
23
|
+
/**
|
|
24
|
+
* Mock 账号配置
|
|
25
|
+
*
|
|
26
|
+
* 写成 `type` 而不是 `interface` 是必要的:`AdapterProvider<T>` 的默认实参是
|
|
27
|
+
* `Record<string, unknown>`,而 TS 只给**类型别名**隐式索引签名,interface 没有 ——
|
|
28
|
+
* 用 interface 的话 `AdapterProvider<MockAccountConfig>` 赋给 `AdapterProvider`
|
|
29
|
+
* (`ctx.registerAdapter` 的形参类型)会编译不过。
|
|
30
|
+
*/
|
|
31
|
+
export type MockAccountConfig = {
|
|
32
|
+
/** 账号在"平台"上的 id,会成为 `bot.selfId` */
|
|
33
|
+
selfId: string;
|
|
34
|
+
/** 账号昵称 */
|
|
35
|
+
nickname?: string;
|
|
36
|
+
};
|
|
37
|
+
/** 一条被 Mock 记下来的发送 */
|
|
38
|
+
export interface SentMessage {
|
|
39
|
+
/** 发出这条消息的账号 selfId */
|
|
40
|
+
selfId: string;
|
|
41
|
+
/** 发送目标 */
|
|
42
|
+
target: SendTarget;
|
|
43
|
+
/** 已展平的消息段 */
|
|
44
|
+
message: Segment[];
|
|
45
|
+
/** 纯文本视图,断言基本都用它 */
|
|
46
|
+
text: string;
|
|
47
|
+
/** 发送选项(内核填的分片/引用信息也在里面) */
|
|
48
|
+
opts: SendOptions | undefined;
|
|
49
|
+
/** Mock 生成的消息 id */
|
|
50
|
+
messageId: string;
|
|
51
|
+
/** 合并转发的节点;普通消息为 undefined */
|
|
52
|
+
nodes: readonly ForwardNode[] | undefined;
|
|
53
|
+
}
|
|
54
|
+
/** 一次被记下来的原生 API 调用 */
|
|
55
|
+
export interface RecordedCall {
|
|
56
|
+
/** API 名 */
|
|
57
|
+
action: string;
|
|
58
|
+
/** 参数 */
|
|
59
|
+
params: Record<string, unknown> | undefined;
|
|
60
|
+
}
|
|
61
|
+
/** 构造一条私聊消息的选项 */
|
|
62
|
+
export interface MockPrivateOptions {
|
|
63
|
+
/** 发送者 id,缺省 `"20000"` */
|
|
64
|
+
uid?: string;
|
|
65
|
+
/** 发送者昵称 */
|
|
66
|
+
name?: string;
|
|
67
|
+
/** 直接指定消息段;给了就忽略 `text` 参数 */
|
|
68
|
+
message?: Segment[];
|
|
69
|
+
/** 引用的消息 id */
|
|
70
|
+
quote?: string;
|
|
71
|
+
/** 平台细分类型,如 `"friend"` / `"temp"` */
|
|
72
|
+
subType?: string;
|
|
73
|
+
}
|
|
74
|
+
/** 构造一条群消息的选项 */
|
|
75
|
+
export interface MockGroupOptions extends MockPrivateOptions {
|
|
76
|
+
/** 群 id,缺省 `"700000"` */
|
|
77
|
+
gid?: string;
|
|
78
|
+
/** 发送者在群里的角色,缺省 `"member"`;测 `e.isGroupAdmin` 时改这里 */
|
|
79
|
+
role?: GroupRole;
|
|
80
|
+
/** 是否 @ 了机器人:true 时在消息最前面插一个 at 段 */
|
|
81
|
+
atMe?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Mock 驱动
|
|
85
|
+
*
|
|
86
|
+
* 除 `BotDriver` 的能力外,多出一组"从平台方向往内核里灌事件"的方法 ——
|
|
87
|
+
* 真适配器里这件事由 socket 回调触发,测试里由这些方法代劳。
|
|
88
|
+
*/
|
|
89
|
+
export interface MockDriver extends BotDriver {
|
|
90
|
+
/** 内核给这个账号的宿主对象(`kv` / `signal` / `route` 都在上面) */
|
|
91
|
+
readonly host: AdapterHost;
|
|
92
|
+
/** 校验后的账号配置 */
|
|
93
|
+
readonly config: MockAccountConfig;
|
|
94
|
+
/** `connect()` 被调用过几次,测退避重连用 */
|
|
95
|
+
readonly connects: number;
|
|
96
|
+
/** `disconnect()` 被调用过几次 */
|
|
97
|
+
readonly disconnects: number;
|
|
98
|
+
/**
|
|
99
|
+
* 投递一个任意事件
|
|
100
|
+
* @param event 已经是通用模型的事件
|
|
101
|
+
*/
|
|
102
|
+
receive(event: IncomingEvent): void;
|
|
103
|
+
/**
|
|
104
|
+
* 投递一条私聊消息
|
|
105
|
+
* @param text 消息内容,支持裸字符串与嵌套数组
|
|
106
|
+
* @param opts 构造选项
|
|
107
|
+
* @returns 投递出去的那个事件,便于断言 `messageId`
|
|
108
|
+
*/
|
|
109
|
+
receivePrivate(text: MessageContent, opts?: MockPrivateOptions): IncomingMessageEvent;
|
|
110
|
+
/**
|
|
111
|
+
* 投递一条群消息
|
|
112
|
+
* @param text 消息内容
|
|
113
|
+
* @param opts 构造选项
|
|
114
|
+
* @returns 投递出去的那个事件
|
|
115
|
+
*/
|
|
116
|
+
receiveGroup(text: MessageContent, opts?: MockGroupOptions): IncomingMessageEvent;
|
|
117
|
+
/**
|
|
118
|
+
* 模拟"连接被对端关闭"
|
|
119
|
+
*
|
|
120
|
+
* 经由 `host.setStatus("offline")`,因此内核会执行完整的下线流程
|
|
121
|
+
* (摘除 Bot 注册表条目、派发 `bot/offline`、安排退避重连),而不仅是修改一个状态字段。
|
|
122
|
+
* @param reason 下线原因,会出现在账号状态里
|
|
123
|
+
*/
|
|
124
|
+
goOffline(reason?: string): void;
|
|
125
|
+
}
|
|
126
|
+
/** 创建 Mock 适配器的选项 */
|
|
127
|
+
export interface MockAdapterOptions {
|
|
128
|
+
/** 适配器 id,缺省 `"mock"` */
|
|
129
|
+
id?: string;
|
|
130
|
+
/** 平台标识,缺省与 id 相同 */
|
|
131
|
+
platform?: string;
|
|
132
|
+
/** 本账号声明的可选能力,缺省撤回 + 合并转发 */
|
|
133
|
+
caps?: readonly BotCapability[];
|
|
134
|
+
/**
|
|
135
|
+
* 让 `connect()` 固定失败
|
|
136
|
+
*
|
|
137
|
+
* 给了字符串就以它为错误消息抛出,用来测"连接失败不进 Bot 注册表、
|
|
138
|
+
* 账号状态变 error、排了退避重连"这条路径。
|
|
139
|
+
*/
|
|
140
|
+
failConnect?: string;
|
|
141
|
+
/**
|
|
142
|
+
* `callApi` 的实现
|
|
143
|
+
*
|
|
144
|
+
* 缺省抛错 —— 内存 Mock 没有"平台原生 API"这回事,静默返回 undefined
|
|
145
|
+
* 只会让依赖它的测试以一个更难懂的形式失败。
|
|
146
|
+
* @param action API 名
|
|
147
|
+
* @param params 参数
|
|
148
|
+
* @returns 平台返回值
|
|
149
|
+
*/
|
|
150
|
+
callApi?: (action: string, params?: Record<string, unknown>) => unknown;
|
|
151
|
+
}
|
|
152
|
+
/** Mock 适配器句柄 */
|
|
153
|
+
export interface MockAdapter {
|
|
154
|
+
/** 交给 `ctx.registerAdapter()` 的提供方 */
|
|
155
|
+
readonly provider: AdapterProvider<MockAccountConfig>;
|
|
156
|
+
/** 已创建的全部驱动,按创建顺序 */
|
|
157
|
+
readonly drivers: readonly MockDriver[];
|
|
158
|
+
/** 全部发送记录(多账号共用一份,按 `selfId` 区分) */
|
|
159
|
+
readonly sent: readonly SentMessage[];
|
|
160
|
+
/** 全部发送记录的纯文本视图 */
|
|
161
|
+
readonly texts: readonly string[];
|
|
162
|
+
/** 被撤回过的消息 id */
|
|
163
|
+
readonly recalled: readonly string[];
|
|
164
|
+
/** 被调用过的原生 API */
|
|
165
|
+
readonly calls: readonly RecordedCall[];
|
|
166
|
+
/**
|
|
167
|
+
* 唯一那个驱动
|
|
168
|
+
*
|
|
169
|
+
* 单账号测试里省一次 `drivers[0]!`。
|
|
170
|
+
* @throws 还没有账号连上来时;错误信息里写了该先调什么
|
|
171
|
+
*/
|
|
172
|
+
readonly driver: MockDriver;
|
|
173
|
+
/**
|
|
174
|
+
* 等到累计发出了 `count` 条消息
|
|
175
|
+
*
|
|
176
|
+
* @param count 期望的累计条数,缺省 1
|
|
177
|
+
* @param timeoutMs 等待上限,缺省 2000
|
|
178
|
+
* @returns 前 `count` 条发送记录
|
|
179
|
+
* @throws 超时;错误信息里带上实际已发出的内容
|
|
180
|
+
*/
|
|
181
|
+
waitForSend(count?: number, timeoutMs?: number): Promise<readonly SentMessage[]>;
|
|
182
|
+
/**
|
|
183
|
+
* 最后一条发送记录
|
|
184
|
+
* @returns 发送记录;一条都没发过时 undefined
|
|
185
|
+
*/
|
|
186
|
+
last(): SentMessage | undefined;
|
|
187
|
+
/** 清空发送/撤回/调用记录(驱动本身保留) */
|
|
188
|
+
reset(): void;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 创建一个内存 Mock 适配器
|
|
192
|
+
*
|
|
193
|
+
* 典型用法(完整例子见 kernel/runtime.test.ts):
|
|
194
|
+
* ```ts
|
|
195
|
+
* const mock = createMockAdapter()
|
|
196
|
+
* app.runtime.adapters.register(mock.provider, "test-plugin")
|
|
197
|
+
* await app.runtime.accounts.create("mock", { selfId: "10000" })
|
|
198
|
+
* mock.driver.receivePrivate("#ping")
|
|
199
|
+
* const [reply] = await mock.waitForSend()
|
|
200
|
+
* ```
|
|
201
|
+
* @param opts 选项
|
|
202
|
+
* @returns Mock 适配器句柄
|
|
203
|
+
*/
|
|
204
|
+
export declare function createMockAdapter(opts?: MockAdapterOptions): MockAdapter;
|
|
205
|
+
//# sourceMappingURL=mock-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-adapter.d.ts","sourceRoot":"","sources":["../../src/testing/mock-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { seg, textOf, toSegments } from "../message/segment.js";
|
|
2
|
+
/** 缺省适配器 id */
|
|
3
|
+
const DEFAULT_ID = "mock";
|
|
4
|
+
/** 缺省账号昵称 */
|
|
5
|
+
const DEFAULT_NICKNAME = "Mock Bot";
|
|
6
|
+
/** 缺省的消息发送者 id */
|
|
7
|
+
const DEFAULT_UID = "20000";
|
|
8
|
+
/** 缺省群 id */
|
|
9
|
+
const DEFAULT_GID = "700000";
|
|
10
|
+
/** `waitForSend()` 的缺省等待上限毫秒 */
|
|
11
|
+
const DEFAULT_WAIT = 2000;
|
|
12
|
+
/** 缺省声明的可选能力:撤回与合并转发,正好对应下面真的实现了的两个可选方法 */
|
|
13
|
+
const DEFAULT_CAPS = ["recall", "forward"];
|
|
14
|
+
/** 账号配置的表单描述,WebUI 的"添加账号"表单由它生成 */
|
|
15
|
+
const ACCOUNT_SCHEMA = {
|
|
16
|
+
type: "object",
|
|
17
|
+
title: "内存 Mock 账号",
|
|
18
|
+
properties: {
|
|
19
|
+
selfId: {
|
|
20
|
+
type: "string",
|
|
21
|
+
title: "账号 id",
|
|
22
|
+
description: "该字段取值任意,Mock 适配器不执行实际登录",
|
|
23
|
+
default: "10000",
|
|
24
|
+
required: true,
|
|
25
|
+
placeholder: "10000"
|
|
26
|
+
},
|
|
27
|
+
nickname: {
|
|
28
|
+
type: "string",
|
|
29
|
+
title: "昵称",
|
|
30
|
+
default: DEFAULT_NICKNAME
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* 创建一个内存 Mock 适配器
|
|
36
|
+
*
|
|
37
|
+
* 典型用法(完整例子见 kernel/runtime.test.ts):
|
|
38
|
+
* ```ts
|
|
39
|
+
* const mock = createMockAdapter()
|
|
40
|
+
* app.runtime.adapters.register(mock.provider, "test-plugin")
|
|
41
|
+
* await app.runtime.accounts.create("mock", { selfId: "10000" })
|
|
42
|
+
* mock.driver.receivePrivate("#ping")
|
|
43
|
+
* const [reply] = await mock.waitForSend()
|
|
44
|
+
* ```
|
|
45
|
+
* @param opts 选项
|
|
46
|
+
* @returns Mock 适配器句柄
|
|
47
|
+
*/
|
|
48
|
+
export function createMockAdapter(opts = {}) {
|
|
49
|
+
const id = opts.id ?? DEFAULT_ID;
|
|
50
|
+
const platform = opts.platform ?? id;
|
|
51
|
+
const caps = new Set(opts.caps ?? DEFAULT_CAPS);
|
|
52
|
+
/** 发送记录 */
|
|
53
|
+
const sent = [];
|
|
54
|
+
/** 撤回记录 */
|
|
55
|
+
const recalled = [];
|
|
56
|
+
/** 原生 API 调用记录 */
|
|
57
|
+
const calls = [];
|
|
58
|
+
/** 已创建的驱动 */
|
|
59
|
+
const drivers = [];
|
|
60
|
+
/** 挂起的 `waitForSend()` */
|
|
61
|
+
const waiters = new Set();
|
|
62
|
+
/** 自增序号,用来生成消息 id;不用时间戳是为了让断言可预期 */
|
|
63
|
+
let counter = 0;
|
|
64
|
+
/**
|
|
65
|
+
* 取下一个消息 id
|
|
66
|
+
* @returns 形如 `mock-msg-1` 的 id
|
|
67
|
+
*/
|
|
68
|
+
const nextId = () => {
|
|
69
|
+
counter += 1;
|
|
70
|
+
return `${id}-msg-${counter}`;
|
|
71
|
+
};
|
|
72
|
+
/** 唤醒条件已满足的等待者 */
|
|
73
|
+
const notify = () => {
|
|
74
|
+
for (const waiter of [...waiters]) {
|
|
75
|
+
if (sent.length >= waiter.count) {
|
|
76
|
+
waiters.delete(waiter);
|
|
77
|
+
waiter.wake();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* 记一条发送
|
|
83
|
+
* @param selfId 发出者
|
|
84
|
+
* @param target 目标
|
|
85
|
+
* @param message 消息段
|
|
86
|
+
* @param sendOpts 发送选项
|
|
87
|
+
* @param nodes 合并转发节点
|
|
88
|
+
* @returns 发送结果
|
|
89
|
+
*/
|
|
90
|
+
const record = (selfId, target, message, sendOpts, nodes) => {
|
|
91
|
+
const messageId = nextId();
|
|
92
|
+
sent.push({ selfId, target, message, text: textOf(message), opts: sendOpts, messageId, nodes });
|
|
93
|
+
notify();
|
|
94
|
+
return { ok: true, messageId, time: Date.now() };
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* 造一个 Mock 驱动
|
|
98
|
+
* @param config 账号配置
|
|
99
|
+
* @param host 内核给的宿主
|
|
100
|
+
* @returns 驱动
|
|
101
|
+
*/
|
|
102
|
+
const createDriver = (config, host) => {
|
|
103
|
+
const selfId = config.selfId;
|
|
104
|
+
const nickname = config.nickname ?? DEFAULT_NICKNAME;
|
|
105
|
+
/** 是否在线 */
|
|
106
|
+
let online = false;
|
|
107
|
+
/** connect 次数 */
|
|
108
|
+
let connects = 0;
|
|
109
|
+
/** disconnect 次数 */
|
|
110
|
+
let disconnects = 0;
|
|
111
|
+
/**
|
|
112
|
+
* 造一个群成员
|
|
113
|
+
* @param gid 群 id
|
|
114
|
+
* @param uid 用户 id
|
|
115
|
+
* @param role 角色
|
|
116
|
+
* @returns 成员信息
|
|
117
|
+
*/
|
|
118
|
+
const member = (gid, uid, role = "member") => ({
|
|
119
|
+
uid,
|
|
120
|
+
gid,
|
|
121
|
+
role,
|
|
122
|
+
name: uid === selfId ? nickname : `用户${uid}`
|
|
123
|
+
});
|
|
124
|
+
const driver = {
|
|
125
|
+
host,
|
|
126
|
+
config,
|
|
127
|
+
selfId,
|
|
128
|
+
platform,
|
|
129
|
+
adapterId: id,
|
|
130
|
+
nickname,
|
|
131
|
+
caps,
|
|
132
|
+
get online() {
|
|
133
|
+
return online;
|
|
134
|
+
},
|
|
135
|
+
get connects() {
|
|
136
|
+
return connects;
|
|
137
|
+
},
|
|
138
|
+
get disconnects() {
|
|
139
|
+
return disconnects;
|
|
140
|
+
},
|
|
141
|
+
async connect() {
|
|
142
|
+
connects += 1;
|
|
143
|
+
if (opts.failConnect !== undefined)
|
|
144
|
+
throw new Error(opts.failConnect);
|
|
145
|
+
online = true;
|
|
146
|
+
return Promise.resolve();
|
|
147
|
+
},
|
|
148
|
+
async disconnect() {
|
|
149
|
+
disconnects += 1;
|
|
150
|
+
online = false;
|
|
151
|
+
return Promise.resolve();
|
|
152
|
+
},
|
|
153
|
+
async sendMessage(target, content, sendOpts) {
|
|
154
|
+
return Promise.resolve(record(selfId, target, toSegments(content), sendOpts));
|
|
155
|
+
},
|
|
156
|
+
async sendForward(target, nodes) {
|
|
157
|
+
// 转发的文本视图取各节点正文拼接,以使 `texts` 断言对转发同样有效
|
|
158
|
+
const flat = nodes.flatMap(node => node.message ?? []);
|
|
159
|
+
return Promise.resolve(record(selfId, target, flat, undefined, nodes));
|
|
160
|
+
},
|
|
161
|
+
async recallMessage(messageId) {
|
|
162
|
+
recalled.push(messageId);
|
|
163
|
+
return Promise.resolve(true);
|
|
164
|
+
},
|
|
165
|
+
async getSelfInfo() {
|
|
166
|
+
return Promise.resolve({ uid: selfId, name: nickname });
|
|
167
|
+
},
|
|
168
|
+
async getFriend(uid) {
|
|
169
|
+
return Promise.resolve({ uid, name: `用户${uid}` });
|
|
170
|
+
},
|
|
171
|
+
async getFriendList() {
|
|
172
|
+
return Promise.resolve([{ uid: DEFAULT_UID, name: `用户${DEFAULT_UID}` }]);
|
|
173
|
+
},
|
|
174
|
+
async getGroup(gid) {
|
|
175
|
+
return Promise.resolve({ gid, name: `Mock 群 ${gid}`, memberCount: 2 });
|
|
176
|
+
},
|
|
177
|
+
async getGroupList() {
|
|
178
|
+
return Promise.resolve([{ gid: DEFAULT_GID, name: `Mock 群 ${DEFAULT_GID}`, memberCount: 2 }]);
|
|
179
|
+
},
|
|
180
|
+
async getGroupMember(gid, uid) {
|
|
181
|
+
return Promise.resolve(member(gid, uid));
|
|
182
|
+
},
|
|
183
|
+
async getGroupMemberList(gid) {
|
|
184
|
+
return Promise.resolve([member(gid, selfId), member(gid, DEFAULT_UID)]);
|
|
185
|
+
},
|
|
186
|
+
async callApi(action, params) {
|
|
187
|
+
calls.push({ action, params });
|
|
188
|
+
if (!opts.callApi) {
|
|
189
|
+
throw new Error(`内存 Mock 适配器没有平台原生 API(收到调用 ${action});需要的话给 createMockAdapter 传 callApi`);
|
|
190
|
+
}
|
|
191
|
+
return (await opts.callApi(action, params));
|
|
192
|
+
},
|
|
193
|
+
receive(event) {
|
|
194
|
+
host.submit(event);
|
|
195
|
+
},
|
|
196
|
+
receivePrivate(text, o = {}) {
|
|
197
|
+
const uid = o.uid ?? DEFAULT_UID;
|
|
198
|
+
const event = {
|
|
199
|
+
kind: "message",
|
|
200
|
+
scene: "private",
|
|
201
|
+
subType: o.subType ?? "friend",
|
|
202
|
+
messageId: nextId(),
|
|
203
|
+
message: o.message ?? toSegments(text),
|
|
204
|
+
sender: { uid, name: o.name ?? `用户${uid}` }
|
|
205
|
+
};
|
|
206
|
+
if (o.quote !== undefined)
|
|
207
|
+
event.quote = { messageId: o.quote };
|
|
208
|
+
host.submit(event);
|
|
209
|
+
return event;
|
|
210
|
+
},
|
|
211
|
+
receiveGroup(text, o = {}) {
|
|
212
|
+
const gid = o.gid ?? DEFAULT_GID;
|
|
213
|
+
const uid = o.uid ?? DEFAULT_UID;
|
|
214
|
+
const body = o.message ?? toSegments(text);
|
|
215
|
+
const event = {
|
|
216
|
+
kind: "message",
|
|
217
|
+
scene: "group",
|
|
218
|
+
subType: o.subType ?? "normal",
|
|
219
|
+
messageId: nextId(),
|
|
220
|
+
message: o.atMe === true ? [seg.at(selfId), ...body] : body,
|
|
221
|
+
sender: { uid, gid, role: o.role ?? "member", name: o.name ?? `用户${uid}` },
|
|
222
|
+
group: { gid, name: `Mock 群 ${gid}` }
|
|
223
|
+
};
|
|
224
|
+
if (o.quote !== undefined)
|
|
225
|
+
event.quote = { messageId: o.quote };
|
|
226
|
+
host.submit(event);
|
|
227
|
+
return event;
|
|
228
|
+
},
|
|
229
|
+
goOffline(reason) {
|
|
230
|
+
online = false;
|
|
231
|
+
host.setStatus("offline", { error: reason ?? "Mock 主动下线" });
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
return driver;
|
|
235
|
+
};
|
|
236
|
+
const provider = {
|
|
237
|
+
id,
|
|
238
|
+
name: "内存 Mock 适配器",
|
|
239
|
+
description: "不连任何平台,事件由测试代码直接灌进来",
|
|
240
|
+
platform,
|
|
241
|
+
accountSchema: ACCOUNT_SCHEMA,
|
|
242
|
+
validateAccount(input) {
|
|
243
|
+
if (typeof input !== "object" || input === null)
|
|
244
|
+
throw new Error("Mock 账号配置必须是一个对象");
|
|
245
|
+
const raw = input;
|
|
246
|
+
const selfId = raw.selfId;
|
|
247
|
+
if (typeof selfId !== "string" || selfId === "")
|
|
248
|
+
throw new Error("Mock 账号配置缺少 selfId");
|
|
249
|
+
const nickname = raw.nickname;
|
|
250
|
+
return { selfId, nickname: typeof nickname === "string" ? nickname : DEFAULT_NICKNAME };
|
|
251
|
+
},
|
|
252
|
+
createBot(account, host) {
|
|
253
|
+
const driver = createDriver(account, host);
|
|
254
|
+
drivers.push(driver);
|
|
255
|
+
return driver;
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
return {
|
|
259
|
+
provider,
|
|
260
|
+
drivers,
|
|
261
|
+
sent,
|
|
262
|
+
recalled,
|
|
263
|
+
calls,
|
|
264
|
+
get texts() {
|
|
265
|
+
return sent.map(item => item.text);
|
|
266
|
+
},
|
|
267
|
+
get driver() {
|
|
268
|
+
const first = drivers[0];
|
|
269
|
+
if (!first)
|
|
270
|
+
throw new Error("还没有 Mock 驱动:先注册 provider 再 accounts.create(),且要等 create() 返回");
|
|
271
|
+
return first;
|
|
272
|
+
},
|
|
273
|
+
async waitForSend(count = 1, timeoutMs = DEFAULT_WAIT) {
|
|
274
|
+
if (sent.length < count) {
|
|
275
|
+
await new Promise((resolve, reject) => {
|
|
276
|
+
// wake 要清定时器、定时器要摘等待者,两边互相引用;用一个小盒子打断这个循环
|
|
277
|
+
const box = {};
|
|
278
|
+
const waiter = {
|
|
279
|
+
count,
|
|
280
|
+
wake: () => {
|
|
281
|
+
clearTimeout(box.timer);
|
|
282
|
+
resolve();
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
box.timer = setTimeout(() => {
|
|
286
|
+
waiters.delete(waiter);
|
|
287
|
+
// 附带已发出的内容:见文件头第 3 条
|
|
288
|
+
const got = sent.length === 0 ? "(尚无任何发送)" : sent.map(item => JSON.stringify(item.text)).join("、");
|
|
289
|
+
reject(new Error(`等待第 ${count} 条发送超过 ${timeoutMs}ms 仍未到达,目前已发出 ${sent.length} 条:${got}`));
|
|
290
|
+
}, timeoutMs);
|
|
291
|
+
// 用例断言完毕后,该定时器不应继续阻塞 vitest 的收尾流程
|
|
292
|
+
box.timer.unref?.();
|
|
293
|
+
waiters.add(waiter);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
return sent.slice(0, count);
|
|
297
|
+
},
|
|
298
|
+
last() {
|
|
299
|
+
return sent[sent.length - 1];
|
|
300
|
+
},
|
|
301
|
+
reset() {
|
|
302
|
+
sent.length = 0;
|
|
303
|
+
recalled.length = 0;
|
|
304
|
+
calls.length = 0;
|
|
305
|
+
counter = 0;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=mock-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-adapter.js","sourceRoot":"","sources":["../../src/testing/mock-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 模块职责:对象深操作(合并、克隆、按路径读写、差异路径计算)
|
|
3
|
+
* 依赖方向:无
|
|
4
|
+
* 生命周期:纯函数
|
|
5
|
+
* 注意事项:配置系统的地基。`diffPaths` 算出实际变化的叶子路径,故配置变更只通知
|
|
6
|
+
* 关心那些路径的订阅者,而不是让每个读配置的地方全量重算。
|
|
7
|
+
*
|
|
8
|
+
* **数组是整体替换,不逐元素合并。** 配置里的数组(主人列表、黑名单)语义上是
|
|
9
|
+
* "一个值",逐元素合并会让使用者无法删除默认项。
|
|
10
|
+
*/
|
|
11
|
+
/** 可作为配置节点的普通对象 */
|
|
12
|
+
export type PlainObject = Record<string, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* 判断是否为普通对象(排除数组、null、Date、Buffer、类实例等)
|
|
15
|
+
* @param value 待判定值
|
|
16
|
+
* @returns 是否为普通对象
|
|
17
|
+
*/
|
|
18
|
+
export declare function isPlainObject(value: unknown): value is PlainObject;
|
|
19
|
+
/**
|
|
20
|
+
* 深克隆
|
|
21
|
+
*
|
|
22
|
+
* 优先用 `structuredClone`(Node 17+ 内置,能处理 Map/Set/Date/循环引用),
|
|
23
|
+
* 遇到函数等不可克隆值时退回浅拷贝语义。
|
|
24
|
+
* @param value 源值
|
|
25
|
+
* @returns 克隆结果
|
|
26
|
+
*/
|
|
27
|
+
export declare function deepClone<T>(value: T): T;
|
|
28
|
+
/**
|
|
29
|
+
* 深合并:把 `source` 覆盖到 `target` 的副本上
|
|
30
|
+
*
|
|
31
|
+
* - 普通对象递归合并
|
|
32
|
+
* - 数组、`Date` 等整体替换
|
|
33
|
+
* - `source` 中值为 `undefined` 的键被忽略(不会把 target 的值抹成 undefined)
|
|
34
|
+
* @param target 基准值(不被修改)
|
|
35
|
+
* @param source 覆盖值
|
|
36
|
+
* @returns 合并后的新对象
|
|
37
|
+
*/
|
|
38
|
+
export declare function deepMerge<T extends PlainObject>(target: T, source: PlainObject | undefined): T;
|
|
39
|
+
/**
|
|
40
|
+
* 深比较
|
|
41
|
+
* @param a 左值
|
|
42
|
+
* @param b 右值
|
|
43
|
+
* @returns 是否深度相等
|
|
44
|
+
*/
|
|
45
|
+
export declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* 把点分路径切成键数组
|
|
48
|
+
*
|
|
49
|
+
* 支持 `a.b[0].c` 与 `a.b.0.c` 两种写法。
|
|
50
|
+
* @param path 路径字符串
|
|
51
|
+
* @returns 键数组
|
|
52
|
+
*/
|
|
53
|
+
export declare function splitPath(path: string): string[];
|
|
54
|
+
/**
|
|
55
|
+
* 按路径取值
|
|
56
|
+
* @param obj 源对象
|
|
57
|
+
* @param path 点分路径;空串返回 obj 本身
|
|
58
|
+
* @returns 值;路径不存在时 undefined
|
|
59
|
+
*/
|
|
60
|
+
export declare function getPath(obj: unknown, path: string): unknown;
|
|
61
|
+
/**
|
|
62
|
+
* 按路径写值(原地修改)
|
|
63
|
+
*
|
|
64
|
+
* 中间层不存在时自动创建:下一级键是纯数字则建数组,否则建对象。
|
|
65
|
+
* @param obj 目标对象
|
|
66
|
+
* @param path 点分路径
|
|
67
|
+
* @param value 值
|
|
68
|
+
* @throws 当路径为空或中间层是不可写入的标量时
|
|
69
|
+
*/
|
|
70
|
+
export declare function setPath(obj: PlainObject, path: string, value: unknown): void;
|
|
71
|
+
/**
|
|
72
|
+
* 按路径删除(原地修改)
|
|
73
|
+
* @param obj 目标对象
|
|
74
|
+
* @param path 点分路径
|
|
75
|
+
* @returns 是否确实删掉了什么
|
|
76
|
+
*/
|
|
77
|
+
export declare function deletePath(obj: PlainObject, path: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* 计算两个对象间发生变化的**叶子路径**
|
|
80
|
+
*
|
|
81
|
+
* 这是细粒度配置失效的核心:改了 `bot.masterQQ` 就只通知订阅
|
|
82
|
+
* `bot.masterQQ`(或其祖先 `bot`)的人,不打扰订阅 `render.*` 的人。
|
|
83
|
+
*
|
|
84
|
+
* 数组视为叶子(整体变化),不下钻元素。
|
|
85
|
+
* @param before 旧值
|
|
86
|
+
* @param after 新值
|
|
87
|
+
* @param prefix 内部递归用的路径前缀
|
|
88
|
+
* @returns 变化路径列表,已去重
|
|
89
|
+
*/
|
|
90
|
+
export declare function diffPaths(before: unknown, after: unknown, prefix?: string): string[];
|
|
91
|
+
/**
|
|
92
|
+
* 判断某条变化路径是否影响到订阅路径
|
|
93
|
+
*
|
|
94
|
+
* 双向前缀匹配:改 `bot` 影响订阅 `bot.masterQQ` 的人(父变子受影响),
|
|
95
|
+
* 改 `bot.masterQQ` 也影响订阅 `bot` 的人(子变父受影响)。
|
|
96
|
+
* @param changed 发生变化的路径
|
|
97
|
+
* @param watched 订阅的路径;空串表示订阅全部
|
|
98
|
+
* @returns 是否受影响
|
|
99
|
+
*/
|
|
100
|
+
export declare function pathAffects(changed: string, watched: string): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* 摘出对象里的指定路径,组成新对象
|
|
103
|
+
* @param obj 源对象
|
|
104
|
+
* @param paths 路径列表
|
|
105
|
+
* @returns 只含这些路径的新对象
|
|
106
|
+
*/
|
|
107
|
+
export declare function pickPaths(obj: PlainObject, paths: readonly string[]): PlainObject;
|
|
108
|
+
//# sourceMappingURL=deep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep.d.ts","sourceRoot":"","sources":["../../src/util/deep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,mBAAmB;AACnB,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEjD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAKlE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAMxC;AAiBD;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,CAAC,CAiB9F;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAwBzD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMhD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAS3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CA2B5E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkBlE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE,CAehF;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAIrE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CAOjF"}
|