@cmtlyt/lingshu-toolkit 0.5.0 → 0.7.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.
Files changed (211) hide show
  1. package/README.md +10 -0
  2. package/dist/665.js +1 -0
  3. package/dist/893.js +1 -0
  4. package/dist/react/index.js +1 -205
  5. package/dist/react/use-boolean/index.d.ts +2 -1
  6. package/dist/react/use-boolean/index.js +1 -16
  7. package/dist/react/use-controllable-value/index.d.ts +3 -3
  8. package/dist/react/use-controllable-value/index.js +1 -32
  9. package/dist/react/use-counter/index.d.ts +2 -2
  10. package/dist/react/use-counter/index.js +1 -49
  11. package/dist/react/use-force-update/index.d.ts +2 -1
  12. package/dist/react/use-force-update/index.js +1 -6
  13. package/dist/react/use-mount/index.d.ts +2 -1
  14. package/dist/react/use-mount/index.js +1 -16
  15. package/dist/react/use-ref-state/index.d.ts +3 -2
  16. package/dist/react/use-ref-state/index.js +1 -33
  17. package/dist/react/use-storage/index.d.ts +2 -1
  18. package/dist/react/use-storage/index.js +1 -15
  19. package/dist/react/use-title/index.d.ts +2 -2
  20. package/dist/react/use-title/index.js +1 -24
  21. package/dist/react/use-toggle/index.d.ts +4 -4
  22. package/dist/react/use-toggle/index.js +1 -26
  23. package/dist/react/use-valid-data/index.d.ts +5 -4
  24. package/dist/react/use-valid-data/index.js +1 -14
  25. package/dist/shared/allx/index.d.ts +2 -1
  26. package/dist/shared/allx/index.js +1 -44
  27. package/dist/shared/allx/types.d.ts +6 -0
  28. package/dist/shared/allx/utils.d.ts +9 -7
  29. package/dist/shared/allx/utils.js +1 -94
  30. package/dist/shared/animation/index.d.ts +3 -2
  31. package/dist/shared/animation/index.js +1 -77
  32. package/dist/shared/animation/types.d.ts +8 -0
  33. package/dist/shared/animation/utils.d.ts +3 -10
  34. package/dist/shared/animation/utils.js +1 -134
  35. package/dist/shared/api-controller/create-api.js +1 -79
  36. package/dist/shared/api-controller/index.js +1 -3
  37. package/dist/shared/api-controller/request.js +1 -66
  38. package/dist/shared/api-controller/types.d.ts +26 -27
  39. package/dist/shared/api-controller/utils.d.ts +6 -15
  40. package/dist/shared/api-controller/utils.js +1 -96
  41. package/dist/shared/condition-merge/index.d.ts +6 -6
  42. package/dist/shared/condition-merge/index.js +1 -30
  43. package/dist/shared/create-storage-handler/index.d.ts +4 -3
  44. package/dist/shared/create-storage-handler/index.js +1 -68
  45. package/dist/shared/data-handler/index.d.ts +4 -3
  46. package/dist/shared/data-handler/index.js +1 -77
  47. package/dist/shared/data-handler/tools.d.ts +6 -23
  48. package/dist/shared/data-handler/tools.js +1 -48
  49. package/dist/shared/data-handler/types.d.ts +20 -2
  50. package/dist/shared/data-mixed-manager/constants.js +1 -9
  51. package/dist/shared/data-mixed-manager/index.js +1 -226
  52. package/dist/shared/data-mixed-manager/types.d.ts +1 -2
  53. package/dist/shared/index.d.ts +2 -0
  54. package/dist/shared/index.js +1 -957
  55. package/dist/shared/lock-data/__test__/_helpers/memory-adapters.d.ts +95 -0
  56. package/dist/shared/lock-data/__test__/_helpers/memory-adapters.js +1 -0
  57. package/dist/shared/lock-data/__test__/playground.js +1 -0
  58. package/dist/shared/lock-data/adapters/authority.d.ts +40 -0
  59. package/dist/shared/lock-data/adapters/authority.js +1 -0
  60. package/dist/shared/lock-data/adapters/channel.d.ts +39 -0
  61. package/dist/shared/lock-data/adapters/channel.js +1 -0
  62. package/dist/shared/lock-data/adapters/index.d.ts +58 -0
  63. package/dist/shared/lock-data/adapters/index.js +1 -0
  64. package/dist/shared/lock-data/adapters/logger.d.ts +56 -0
  65. package/dist/shared/lock-data/adapters/logger.js +1 -0
  66. package/dist/shared/lock-data/adapters/session-store.d.ts +37 -0
  67. package/dist/shared/lock-data/adapters/session-store.js +1 -0
  68. package/dist/shared/lock-data/authority/epoch.d.ts +135 -0
  69. package/dist/shared/lock-data/authority/epoch.js +1 -0
  70. package/dist/shared/lock-data/authority/extract.d.ts +107 -0
  71. package/dist/shared/lock-data/authority/extract.js +1 -0
  72. package/dist/shared/lock-data/authority/index.d.ts +182 -0
  73. package/dist/shared/lock-data/authority/index.js +1 -0
  74. package/dist/shared/lock-data/authority/serialize.d.ts +35 -0
  75. package/dist/shared/lock-data/authority/serialize.js +1 -0
  76. package/dist/shared/lock-data/constants.d.ts +46 -0
  77. package/dist/shared/lock-data/constants.js +1 -0
  78. package/dist/shared/lock-data/core/actions-helpers.d.ts +163 -0
  79. package/dist/shared/lock-data/core/actions-helpers.js +1 -0
  80. package/dist/shared/lock-data/core/actions.d.ts +72 -0
  81. package/dist/shared/lock-data/core/actions.js +1 -0
  82. package/dist/shared/lock-data/core/draft.d.ts +64 -0
  83. package/dist/shared/lock-data/core/draft.js +1 -0
  84. package/dist/shared/lock-data/core/entry.d.ts +133 -0
  85. package/dist/shared/lock-data/core/entry.js +1 -0
  86. package/dist/shared/lock-data/core/fanout.d.ts +42 -0
  87. package/dist/shared/lock-data/core/fanout.js +1 -0
  88. package/dist/shared/lock-data/core/readonly-view.d.ts +49 -0
  89. package/dist/shared/lock-data/core/readonly-view.js +1 -0
  90. package/dist/shared/lock-data/core/registry.d.ts +282 -0
  91. package/dist/shared/lock-data/core/registry.js +1 -0
  92. package/dist/shared/lock-data/core/signal.d.ts +33 -0
  93. package/dist/shared/lock-data/core/signal.js +1 -0
  94. package/dist/shared/lock-data/drivers/broadcast-protocol.d.ts +71 -0
  95. package/dist/shared/lock-data/drivers/broadcast-protocol.js +1 -0
  96. package/dist/shared/lock-data/drivers/broadcast-state.d.ts +125 -0
  97. package/dist/shared/lock-data/drivers/broadcast-state.js +1 -0
  98. package/dist/shared/lock-data/drivers/broadcast.d.ts +36 -0
  99. package/dist/shared/lock-data/drivers/broadcast.js +1 -0
  100. package/dist/shared/lock-data/drivers/custom.d.ts +27 -0
  101. package/dist/shared/lock-data/drivers/custom.js +1 -0
  102. package/dist/shared/lock-data/drivers/index.d.ts +59 -0
  103. package/dist/shared/lock-data/drivers/index.js +1 -0
  104. package/dist/shared/lock-data/drivers/local.d.ts +86 -0
  105. package/dist/shared/lock-data/drivers/local.js +1 -0
  106. package/dist/shared/lock-data/drivers/storage-protocol.d.ts +67 -0
  107. package/dist/shared/lock-data/drivers/storage-protocol.js +1 -0
  108. package/dist/shared/lock-data/drivers/storage-state.d.ts +103 -0
  109. package/dist/shared/lock-data/drivers/storage-state.js +1 -0
  110. package/dist/shared/lock-data/drivers/storage.d.ts +71 -0
  111. package/dist/shared/lock-data/drivers/storage.js +1 -0
  112. package/dist/shared/lock-data/drivers/types.d.ts +73 -0
  113. package/dist/shared/lock-data/drivers/types.js +0 -0
  114. package/dist/shared/lock-data/drivers/web-locks.d.ts +123 -0
  115. package/dist/shared/lock-data/drivers/web-locks.js +1 -0
  116. package/dist/shared/lock-data/errors/index.d.ts +12 -0
  117. package/dist/shared/lock-data/errors/index.js +1 -0
  118. package/dist/shared/lock-data/errors/invalid-options-error.d.ts +11 -0
  119. package/dist/shared/lock-data/errors/invalid-options-error.js +1 -0
  120. package/dist/shared/lock-data/errors/lock-aborted-error.d.ts +10 -0
  121. package/dist/shared/lock-data/errors/lock-aborted-error.js +1 -0
  122. package/dist/shared/lock-data/errors/lock-disposed-error.d.ts +14 -0
  123. package/dist/shared/lock-data/errors/lock-disposed-error.js +1 -0
  124. package/dist/shared/lock-data/errors/lock-revoked-error.d.ts +10 -0
  125. package/dist/shared/lock-data/errors/lock-revoked-error.js +1 -0
  126. package/dist/shared/lock-data/errors/lock-timeout-error.d.ts +9 -0
  127. package/dist/shared/lock-data/errors/lock-timeout-error.js +1 -0
  128. package/dist/shared/lock-data/errors/readonly-mutation-error.d.ts +11 -0
  129. package/dist/shared/lock-data/errors/readonly-mutation-error.js +1 -0
  130. package/dist/shared/lock-data/index.d.ts +57 -0
  131. package/dist/shared/lock-data/index.js +1 -0
  132. package/dist/shared/lock-data/types.d.ts +347 -0
  133. package/dist/shared/lock-data/types.js +0 -0
  134. package/dist/shared/lock-data/utils/json-safe.d.ts +69 -0
  135. package/dist/shared/lock-data/utils/json-safe.js +1 -0
  136. package/dist/shared/logger/index.d.ts +2 -2
  137. package/dist/shared/logger/index.js +1 -10
  138. package/dist/shared/priority-queue/index.d.ts +45 -0
  139. package/dist/shared/priority-queue/index.js +1 -0
  140. package/dist/shared/priority-queue/types.d.ts +10 -0
  141. package/dist/shared/priority-queue/types.js +0 -0
  142. package/dist/shared/priority-queue/utils.d.ts +7 -0
  143. package/dist/shared/priority-queue/utils.js +1 -0
  144. package/dist/shared/throw-error/index.d.ts +11 -3
  145. package/dist/shared/throw-error/index.js +1 -10
  146. package/dist/shared/try-call/index.d.ts +3 -3
  147. package/dist/shared/try-call/index.js +1 -59
  148. package/dist/shared/types/index.js +1 -2
  149. package/dist/shared/types/pack.d.ts +2 -2
  150. package/dist/shared/types/pack.js +1 -1
  151. package/dist/shared/utils/base.d.ts +1 -1
  152. package/dist/shared/utils/base.js +1 -6
  153. package/dist/shared/utils/index.js +1 -2
  154. package/dist/shared/utils/verify.d.ts +1 -1
  155. package/dist/shared/utils/verify.js +1 -67
  156. package/dist/shared/with-resolvers/index.d.ts +5 -3
  157. package/dist/shared/with-resolvers/index.js +1 -15
  158. package/dist/vue/index.js +1 -29
  159. package/dist/vue/use-title/index.d.ts +2 -2
  160. package/dist/vue/use-title/index.js +1 -29
  161. package/package.json +27 -27
  162. package/dist/247.js +0 -66
  163. package/dist/707.js +0 -142
  164. package/dist/react/use-force-update/index.test.d.ts +0 -1
  165. package/dist/react/use-mount/index.test.d.ts +0 -1
  166. package/dist/react/use-ref-state/index.test.d.ts +0 -1
  167. package/dist/react/use-storage/index.test.d.ts +0 -1
  168. package/dist/react/use-title/index.test.d.ts +0 -1
  169. package/dist/react/use-toggle/index.test.d.ts +0 -1
  170. package/dist/react/use-valid-data/index.test.d.ts +0 -1
  171. package/dist/shared/allx/__test__/allsettled.test.d.ts +0 -1
  172. package/dist/shared/allx/__test__/basic.test.d.ts +0 -1
  173. package/dist/shared/allx/__test__/circular-dependency.test.d.ts +0 -1
  174. package/dist/shared/allx/__test__/dependency.test.d.ts +0 -1
  175. package/dist/shared/allx/__test__/edge-cases.test.d.ts +0 -1
  176. package/dist/shared/allx/__test__/error-handling.test.d.ts +0 -1
  177. package/dist/shared/allx/__test__/execution-order.test.d.ts +0 -1
  178. package/dist/shared/allx/__test__/falsy-values.test.d.ts +0 -1
  179. package/dist/shared/allx/__test__/performance.test.d.ts +0 -1
  180. package/dist/shared/allx/__test__/type-checking.test.d.ts +0 -1
  181. package/dist/shared/allx/__test__/use-cases.test.d.ts +0 -1
  182. package/dist/shared/animation/__test__/animation-pause-resume.test.d.ts +0 -1
  183. package/dist/shared/animation/__test__/animation.test.d.ts +0 -1
  184. package/dist/shared/animation/__test__/step-animation.test.d.ts +0 -1
  185. package/dist/shared/animation/__test__/utils.test.d.ts +0 -1
  186. package/dist/shared/api-controller/__test__/index.browser.test.d.ts +0 -1
  187. package/dist/shared/api-controller/__test__/index.node.test.d.ts +0 -1
  188. package/dist/shared/condition-merge/index.test-d.js +0 -108
  189. package/dist/shared/condition-merge/index.test.d.ts +0 -1
  190. package/dist/shared/create-storage-handler/index.browser.test.d.ts +0 -1
  191. package/dist/shared/create-storage-handler/index.test.d.ts +0 -1
  192. package/dist/shared/data-handler/index.test.d.ts +0 -1
  193. package/dist/shared/data-mixed-manager/__test__/basic.test.d.ts +0 -1
  194. package/dist/shared/data-mixed-manager/__test__/build-options.test.d.ts +0 -1
  195. package/dist/shared/data-mixed-manager/__test__/constructor-options.test.d.ts +0 -1
  196. package/dist/shared/data-mixed-manager/__test__/data-management.test.d.ts +0 -1
  197. package/dist/shared/data-mixed-manager/__test__/edge-cases.test.d.ts +0 -1
  198. package/dist/shared/data-mixed-manager/__test__/events.browser.test.d.ts +0 -1
  199. package/dist/shared/data-mixed-manager/__test__/events.test.d.ts +0 -1
  200. package/dist/shared/data-mixed-manager/__test__/fixed-slots.test.d.ts +0 -1
  201. package/dist/shared/data-mixed-manager/__test__/insert-mode.test.d.ts +0 -1
  202. package/dist/shared/throw-error/index.test.d.ts +0 -1
  203. package/dist/shared/try-call/index.test.d.ts +0 -1
  204. package/dist/shared/utils/__test__/base.test.d.ts +0 -1
  205. package/dist/shared/utils/__test__/verify.test.d.ts +0 -1
  206. package/dist/shared/with-resolvers/index.test.d.ts +0 -1
  207. package/dist/test/utils.d.ts +0 -13
  208. package/dist/vue/use-title/index.test.d.ts +0 -1
  209. /package/dist/{react/use-boolean/index.test.d.ts → shared/lock-data/__test__/index.test-d.d.ts} +0 -0
  210. /package/dist/{react/use-controllable-value/index.test.d.ts → shared/lock-data/__test__/integration/entry.test-d.d.ts} +0 -0
  211. /package/dist/{react/use-counter/index.test.d.ts → shared/lock-data/__test__/playground.d.ts} +0 -0
@@ -0,0 +1,347 @@
1
+ /**
2
+ * lock-data 模块的公开类型定义
3
+ *
4
+ * 仅包含 API 表面(options / actions / listeners / adapters 等),
5
+ * 内部实现使用的类型(Entry / InstanceRegistry / DriverHandle 等)放在对应模块内部。
6
+ *
7
+ * 对应 RFC.md「附录 A:完整接口索引」章节。
8
+ */
9
+ import type { NEVER_TIMEOUT } from './constants';
10
+ /**
11
+ * 超时参数支持的形态:
12
+ * - number:毫秒数(0 或负数非法,由参数校验层拦截)
13
+ * - NEVER_TIMEOUT:永不超时(业务自控)
14
+ */
15
+ type TimeoutValue = number | typeof NEVER_TIMEOUT;
16
+ /** 跨进程同步模式;本期仅 `'none'` 与 `'storage-authority'` */
17
+ type SyncMode = 'none' | 'storage-authority';
18
+ /**
19
+ * 锁驱动选择模式
20
+ *
21
+ * 对应 RFC.md「能力检测与降级」;`adapters.getLock` 存在时本字段被忽略
22
+ *
23
+ * - `'auto'`(默认):按能力降级链 web-locks → broadcast → storage
24
+ * - `'web-locks'` / `'broadcast'` / `'storage'`:强制使用对应 driver;能力不可用时抛错
25
+ */
26
+ type LockMode = 'auto' | 'web-locks' | 'broadcast' | 'storage';
27
+ /**
28
+ * 持久化策略:
29
+ * - `'session'`(默认):所有 Tab 关闭后重置;协作期的天然语义
30
+ * - `'persistent'`:跨浏览器重启保留;适合用户草稿 / 偏好
31
+ */
32
+ type Persistence = 'session' | 'persistent';
33
+ /** `actions` 内部状态机的公开子集;用于 listeners.onLockStateChange 事件 */
34
+ type LockPhase = 'idle' | 'acquiring' | 'holding' | 'committing' | 'released' | 'revoked' | 'disposed';
35
+ /** revoke 触发原因 */
36
+ type RevokeReason = 'force' | 'timeout' | 'dispose';
37
+ /** `listeners.onSync` 的触发来源 */
38
+ type SyncSource = 'pull-on-acquire' | 'storage-event' | 'pageshow' | 'visibilitychange';
39
+ /** `listeners.onCommit` 的触发来源 */
40
+ type CommitSource = 'update' | 'replace';
41
+ /**
42
+ * Draft 执行期间记录的最小路径变更
43
+ *
44
+ * 同时服务审计(listeners.onCommit)与回滚(revoke / abort 时反向应用)
45
+ *
46
+ * **JSON-only 契约**:lock-data 的 draft 仅支持 JSON 安全类型(plain object / array /
47
+ * string / number(不含 NaN/Infinity)/ boolean / null),故 mutation op 仅有
48
+ * 普通对象属性的 `set` / `delete` 两种。Set / Map / Date / class 实例 等非 JSON
49
+ * 类型在 `createDraftSession` 入口与每次写入处会被显式拒绝(抛 `TypeError`),
50
+ * 详见 `core/draft.ts` 文件顶部「JSON-only 契约」说明。
51
+ *
52
+ * op 语义:
53
+ * - `'set'`:属性写入 / 新增,`path` 指向被修改的属性,`value` 为新值
54
+ * - `'delete'`:属性删除,`path` 指向被删除的属性,`value` 不携带
55
+ */
56
+ type LockDataMutationOp = 'set' | 'delete';
57
+ interface LockDataMutation {
58
+ readonly path: readonly PropertyKey[];
59
+ readonly op: LockDataMutationOp;
60
+ readonly value?: unknown;
61
+ }
62
+ /** 状态流转事件 */
63
+ interface LockStateChangeEvent {
64
+ readonly phase: LockPhase;
65
+ readonly token: string;
66
+ }
67
+ /** revoke 事件 */
68
+ interface RevokeEvent {
69
+ readonly reason: RevokeReason;
70
+ readonly token: string;
71
+ }
72
+ /** commit 事件(仅 commit 成功时触发) */
73
+ interface CommitEvent<T> {
74
+ readonly source: CommitSource;
75
+ readonly token: string;
76
+ readonly rev: number;
77
+ readonly mutations: readonly LockDataMutation[];
78
+ readonly snapshot: T;
79
+ }
80
+ /** sync 事件(仅 syncMode 非 none 时触发) */
81
+ interface SyncEvent<T> {
82
+ readonly source: SyncSource;
83
+ readonly rev: number;
84
+ readonly snapshot: T;
85
+ }
86
+ /** 全部事件监听器;均为可选 */
87
+ interface LockDataListeners<T> {
88
+ onLockStateChange?: (event: LockStateChangeEvent) => void;
89
+ onRevoked?: (event: RevokeEvent) => void;
90
+ onCommit?: (event: CommitEvent<T>) => void;
91
+ onSync?: (event: SyncEvent<T>) => void;
92
+ }
93
+ /** 每次 action 调用级别的覆盖项 */
94
+ interface ActionCallOptions {
95
+ /** 覆盖 options.timeout 中的抢锁部分 */
96
+ acquireTimeout?: TimeoutValue;
97
+ /** 覆盖 options.timeout 中的持锁部分 */
98
+ holdTimeout?: TimeoutValue;
99
+ /** 强制抢占当前持有者 */
100
+ force?: boolean;
101
+ /** 仅影响本次调用的取消信号 */
102
+ signal?: AbortSignal;
103
+ }
104
+ /**
105
+ * 驱动工厂上下文;用户注入自定义 `adapters.getLock` 时 RFC 约定的参数
106
+ *
107
+ * 命名字段与 RFC 「自定义锁驱动」示例对齐,不使用简写
108
+ */
109
+ interface LockDriverContext {
110
+ readonly name: string;
111
+ readonly token: string;
112
+ readonly force: boolean;
113
+ readonly acquireTimeout: TimeoutValue;
114
+ readonly holdTimeout: TimeoutValue;
115
+ readonly signal: AbortSignal;
116
+ }
117
+ /** 锁驱动句柄;由 `adapters.getLock` 返回 */
118
+ interface LockDriverHandle {
119
+ /**
120
+ * 释放锁
121
+ *
122
+ * 返回值兼容 Promises/A+ 规范的最小 thenable(仅需实现 `.then`),
123
+ * 实现侧通过 `Promise.resolve(...).catch(...)` 正规化后挂错误处理
124
+ */
125
+ release: () => void | PromiseLike<void>;
126
+ onRevokedByDriver: (callback: (reason: 'force' | 'timeout') => void) => void;
127
+ }
128
+ /** `AuthorityAdapter` 工厂上下文 */
129
+ interface AuthorityAdapterContext {
130
+ readonly id: string;
131
+ }
132
+ /** `ChannelAdapter` 工厂上下文 */
133
+ interface ChannelAdapterContext {
134
+ readonly id: string;
135
+ readonly channel: 'session' | 'custom';
136
+ }
137
+ /** `SessionStoreAdapter` 工厂上下文 */
138
+ interface SessionStoreAdapterContext {
139
+ readonly id: string;
140
+ }
141
+ interface AuthorityAdapter {
142
+ read: () => string | null;
143
+ write: (raw: string) => void;
144
+ remove: () => void;
145
+ subscribe: (onExternalUpdate: (newValue: string | null) => void) => () => void;
146
+ }
147
+ interface ChannelAdapter {
148
+ postMessage: (message: unknown) => void;
149
+ subscribe: (onMessage: (message: unknown) => void) => () => void;
150
+ close: () => void;
151
+ }
152
+ interface SessionStoreAdapter {
153
+ read: () => string | null;
154
+ write: (value: string) => void;
155
+ }
156
+ interface LoggerAdapter {
157
+ warn: (message: string, ...extras: unknown[]) => void;
158
+ error: (message: string, ...extras: unknown[]) => void;
159
+ debug?: (message: string, ...extras: unknown[]) => void;
160
+ }
161
+ /**
162
+ * 顶层数组类型禁止
163
+ *
164
+ * wrapper Proxy 方案下,顶层数组会触发 `Object.keys(view)` / `JSON.stringify(view)` 的
165
+ * length invariant TypeError、`Array.isArray(view)` 永远返回 `false` 等不可调和的不变量冲突
166
+ *
167
+ * 编译期把 `T extends unknown[]` 排除为 `never`,运行时由 `core/entry.ts` 的 `Array.isArray(awaited)`
168
+ * 双重 fail-fast 拒绝,保证用户面错误信息明确(`InvalidOptionsError`)
169
+ *
170
+ * 对应 RFC.md「顶层数组禁止」章节
171
+ */
172
+ type LockDataValueShape<T> = T extends readonly unknown[] ? never : T;
173
+ /**
174
+ * 所有环境依赖的统一注入入口
175
+ *
176
+ * 设计决策:采用工厂函数(`getXxx(ctx) => Adapter`)而非直接传实例,
177
+ * 理由是锁 / 权威副本 / 通道这些依赖与 id 强绑定,工厂形态允许上层
178
+ * 在首次创建 Entry 时按 id 组装;无 id 作用域的依赖(logger)直接传实例
179
+ *
180
+ * 注:本期不再提供 `clone` 适配器,所有快照派生使用 `JSON.parse(JSON.stringify(...))` 固化语义;
181
+ * `getValue` resolve 后 + `actions.replace(next)` 入参由 `assertJsonSafe` fail-fast 校验,
182
+ * 保证 `entry.dataRef.current` 永远只含 JSON 安全值
183
+ */
184
+ interface LockDataAdapters<_T> {
185
+ getLock?: (ctx: LockDriverContext) => Promise<LockDriverHandle> | LockDriverHandle;
186
+ getAuthority?: (ctx: AuthorityAdapterContext) => AuthorityAdapter | null;
187
+ getChannel?: (ctx: ChannelAdapterContext) => ChannelAdapter | null;
188
+ getSessionStore?: (ctx: SessionStoreAdapterContext) => SessionStoreAdapter | null;
189
+ logger?: LoggerAdapter;
190
+ }
191
+ /**
192
+ * `lockData` 的顶层配置(**单参数 API**)
193
+ *
194
+ * - `getValue` 必传:数据来源唯一入口,返回值禁止为顶层数组(`LockDataValueShape<T>` 类型层排除)
195
+ * - 同步 `getValue()` → `lockData()` 同步返回元组
196
+ * - 异步 `getValue()` → `lockData()` 返回 Promise<元组>,resolve 后才把元组交付给调用方
197
+ *
198
+ * 对应 RFC.md「§3 核心语义」「§API 签名」章节
199
+ */
200
+ interface LockDataOptions<T> {
201
+ /**
202
+ * 锁 id;未传时视为"纯本地只读锁",不参与跨模块 / 跨 Tab 共享
203
+ */
204
+ id?: string;
205
+ /**
206
+ * 数据初始化器(**必传**)
207
+ *
208
+ * - 返回值在类型层被 `LockDataValueShape<T>` 限制:禁止顶层数组(`T extends readonly unknown[]` 排除为 `never`)
209
+ * - 返回 `T` → `lockData` 同步返回元组
210
+ * - 返回 `Promise<T>` → `lockData` 返回 Promise<元组>
211
+ * - 同步 `getValue()` 抛错 → `lockData()` 调用栈直接抛 `LockDisposedError`(Entry 不构造)
212
+ * - 异步 `getValue()` reject → `lockData()` 返回的 Promise reject `LockDisposedError`,`cause` 字段携带原因
213
+ * - 运行时 `Array.isArray(awaited)` 双重 fail-fast 拒绝顶层数组(抛 `InvalidOptionsError`)
214
+ * - resolve 后由 `assertJsonSafe` 校验 JSON 安全(非 JSON-safe 抛 `InvalidOptionsError`)
215
+ */
216
+ getValue: () => LockDataValueShape<T> | Promise<LockDataValueShape<T>>;
217
+ /** 默认抢锁 + 持锁超时,可被 `ActionCallOptions` 覆盖 */
218
+ timeout?: TimeoutValue;
219
+ /**
220
+ * 锁驱动选择;默认 `'auto'`
221
+ *
222
+ * `adapters.getLock` 存在时本字段被忽略(用户自定义 driver 优先级最高)
223
+ */
224
+ mode?: LockMode;
225
+ /** 跨进程同步模式;默认 `'none'` */
226
+ syncMode?: SyncMode;
227
+ /** 持久化策略;默认 `'session'`(仅在 syncMode 非 none 时生效) */
228
+ persistence?: Persistence;
229
+ /** session-probe 等待窗口;默认 100ms */
230
+ sessionProbeTimeout?: number;
231
+ /** 实例级生命周期控制;abort 等价于 dispose() */
232
+ signal?: AbortSignal;
233
+ /** 全部事件监听器 */
234
+ listeners?: LockDataListeners<T>;
235
+ /** 所有环境依赖的注入入口 */
236
+ adapters?: LockDataAdapters<T>;
237
+ }
238
+ /**
239
+ * actions 对象的公开 API
240
+ *
241
+ * 每个方法的语义详见 RFC.md「Actions 实现要点」章节
242
+ */
243
+ interface LockDataActions<T extends object> {
244
+ /** 当前是否持有锁(释放 / revoke 后为 false) */
245
+ readonly isHolding: boolean;
246
+ /** 事务式写入;recipe 失败或被 revoke 时自动回滚 */
247
+ update: (recipe: (draft: T) => void | Promise<void>, callOptions?: ActionCallOptions) => Promise<void>;
248
+ /** 整体替换;等价于一次隐式 update 事务;入参由 `assertJsonSafe` fail-fast 校验 */
249
+ replace: (next: T, callOptions?: ActionCallOptions) => Promise<void>;
250
+ /**
251
+ * 不抢锁的快照读取
252
+ *
253
+ * 返回 `JSON.parse(JSON.stringify(entry.dataRef.current))` 产出的全新对象,
254
+ * 与内部 `dataRef.current` 完全隔离;调用方对返回值的任何 mutate 都不会影响内部状态
255
+ *
256
+ * 对应 RFC.md「actions.snapshot()」章节
257
+ */
258
+ snapshot: () => T;
259
+ /** 手动抢锁;配合连续 update + release 实现多步事务 */
260
+ getLock: (callOptions?: ActionCallOptions) => Promise<void>;
261
+ /**
262
+ * 只还锁,不销毁实例;actions 仍可继续使用
263
+ *
264
+ * 与 `dispose` 的区别:release 对应 getLock,dispose 对应 lockData
265
+ */
266
+ release: () => void;
267
+ /** 还锁 + 销毁实例;调用后本 actions 进入 disposed 终态 */
268
+ dispose: () => Promise<void>;
269
+ }
270
+ /**
271
+ * lockData 返回值
272
+ *
273
+ * 同步初始化时为元组;异步初始化(getValue 返回 Promise 或 syncMode 非 none)时为 Promise<元组>
274
+ *
275
+ * 内部视角类型(第一个元素为裸 T),用于 `core/entry.ts` 及其调用链的实现;
276
+ * 对外公开契约请使用 `LockDataTuple<T>`(第一个元素为 `ReadonlyView<T>`)
277
+ */
278
+ type LockDataResult<T extends object> = readonly [T, LockDataActions<T>];
279
+ /**
280
+ * 深只读视图
281
+ *
282
+ * - 函数类型透传不递归(避免破坏 this / 参数类型)
283
+ * - 对象类型递归加 readonly,所有属性只读
284
+ * - 其他类型(primitive / symbol)原样透传
285
+ *
286
+ * 运行时由 `core/readonly-view.ts::createReadonlyView` 返回深只读 Proxy 保证;
287
+ * 用户通过 `lockData()` 返回的 tuple 第一个元素拿到的即为 `ReadonlyView<T>` 实例
288
+ *
289
+ * 对应 RFC.md「ReadonlyView\<T\>」章节
290
+ *
291
+ * 注:`(...args: any[]) => any` 是 RFC 合同语义(匹配任意函数签名的透传),
292
+ * 无法用 `unknown[]` / `unknown` 替代(否则 `keyof` 分发到函数类型会得出 `never`)
293
+ */
294
+ type ReadonlyView<T> = T extends (...args: never[]) => unknown ? T : T extends object ? {
295
+ readonly [K in keyof T]: ReadonlyView<T[K]>;
296
+ } : T;
297
+ /**
298
+ * lockData 公开契约的返回元组类型
299
+ *
300
+ * 与内部 `LockDataResult<T>` 的区别:第一个元素类型为 `ReadonlyView<T>`(深只读代理),
301
+ * 明确向用户传达"读句柄只读、写操作必须经 `actions.update/replace`"的设计意图
302
+ *
303
+ * 对应 RFC.md「签名」章节
304
+ */
305
+ type LockDataTuple<T extends object> = readonly [ReadonlyView<T>, LockDataActions<T>];
306
+ /**
307
+ * lockData 返回值类型推断(**单签名 + 条件类型自动推断**)
308
+ *
309
+ * 设计动机:避免 `LockDataTuple<T> | Promise<LockDataTuple<T>>` 联合类型在调用点强迫
310
+ * 用户用 `as` 断言或 `instanceof Promise` 分支判断;类型层直接镜像运行时判定优先级,
311
+ * 让 `lockData({ getValue: () => ({}) })` 直接得到元组、`lockData({ getValue: () => Promise.resolve({}) })`
312
+ * 直接得到 Promise,无需 `await` / 断言
313
+ *
314
+ * 判定优先级(与 `core/entry.ts` 运行时分支严格对齐):
315
+ * 1. `O extends { syncMode: 'storage-authority' }`
316
+ * a. 若 `O extends { id: string }` → `Promise<LockDataTuple<T>>`
317
+ * b. 若 `O` 缺 `id` 字段 → `never`(**最严格类型层校验**:`syncMode='storage-authority'`
318
+ * 要求必须传 `id`,否则 authority 无法绑定作用域;编译期 fail-fast 让这种非法组合
319
+ * 在调用点直接类型报错,避免运行时静默 fallback 到 `'none'`)
320
+ * 2. 否则若 `ReturnType<O['getValue']> extends Promise<unknown>` → `Promise<LockDataTuple<T>>`
321
+ * 3. 否则 → `LockDataTuple<T>`
322
+ *
323
+ * 注:判定 1.b 用 `LockDataReturnNeverWithoutId` 做条件分支,避免 `O extends { id: string }`
324
+ * 在 `O` 是宽泛类型(如 `LockDataOptions<T>`)时被推断为 `true` 而绕过校验;
325
+ * 必须严格匹配 `O` 类型字面量中的 `id` 字段
326
+ *
327
+ * 注:第二个泛型参数 `O` 的约束放宽为 `object` 而非 `LockDataOptions<X>`,
328
+ * 是 TypeScript 条件类型推断的**标准协变兜底用法**:
329
+ * - `LockDataOptions<T>` 在 `T` 上是双向不变(`listeners.onCommit` 等回调字段使 `T` 既出现在
330
+ * 协变位置又出现在逆变位置)
331
+ * - 调用 `lockData<const O extends LockDataOptions<LockDataValueShape<LockDataInfer<O>>>>(options: O)`
332
+ * 后,把 `O` 传给 `LockDataReturn<T, O>` 时若约束写成 `LockDataOptions<X>`(无论 `X` 是
333
+ * `T` / `any` / `unknown`),都会因双向不变而拒绝(参见 tsc TS2344)
334
+ * - 条件分支只关心 `O` 是否包含 `syncMode` / `id` / `getValue` 字段,不需要 `O` 是
335
+ * `LockDataOptions` 的子类型;约束放到 `object` 即可(公开签名 `lockData` 的 `O` 约束
336
+ * 已保证调用方传入合法 `LockDataOptions<X>`,类型层条件分支无需重复约束)
337
+ *
338
+ * 对应 RFC.md「§签名」章节 + 决策 #33 §A
339
+ */
340
+ type LockDataReturn<T extends object, O extends object> = O extends {
341
+ syncMode: 'storage-authority';
342
+ } ? O extends {
343
+ id: string;
344
+ } ? Promise<LockDataTuple<T>> : never : O extends {
345
+ getValue: () => infer R;
346
+ } ? R extends Promise<unknown> ? Promise<LockDataTuple<T>> : LockDataTuple<T> : LockDataTuple<T>;
347
+ export type { ActionCallOptions, AuthorityAdapter, AuthorityAdapterContext, ChannelAdapter, ChannelAdapterContext, CommitEvent, CommitSource, LockDataActions, LockDataAdapters, LockDataListeners, LockDataMutation, LockDataMutationOp, LockDataOptions, LockDataResult, LockDataReturn, LockDataTuple, LockDataValueShape, LockDriverContext, LockDriverHandle, LockMode, LockPhase, LockStateChangeEvent, LoggerAdapter, Persistence, ReadonlyView, RevokeEvent, RevokeReason, SessionStoreAdapter, SessionStoreAdapterContext, SyncEvent, SyncMode, SyncSource, TimeoutValue, };
File without changes
@@ -0,0 +1,69 @@
1
+ /**
2
+ * lock-data 模块的 JSON 安全校验工具
3
+ *
4
+ * 设计动机:wrapper 方案下所有进入 `entry.dataRef.current` 的值都必须是 JSON 安全的,
5
+ * 否则 `JSON.parse(JSON.stringify(...))` 会静默丢失 Set / Map / Date / class instance / undefined 等
6
+ *
7
+ * 边界一致:
8
+ * - getValue resolve 后入口走 `assertJsonSafe(awaited, ...)` fail-fast
9
+ * - actions.replace(next) 入口走 `assertJsonSafe(next, ...)` fail-fast
10
+ * - draft.ts 的写入路径同样复用本模块的 assertJsonSafe(共享同一份语义)
11
+ *
12
+ * 顶层数组在类型层(`LockDataValueShape<T>`)已被排除为 `never`;运行时通过
13
+ * `assertNotTopLevelArray` 双重 fail-fast 拦截类型擦除路径下的误用
14
+ *
15
+ * 对应 fixes/api-getvalue-only-redesign.md §14.4 / RFC.md「JSON 安全契约」章节
16
+ */
17
+ /**
18
+ * 描述非 JSON 值的具体类型,用于错误信息
19
+ *
20
+ * 例:`Set` / `Map` / `Date` / `class instance (Foo)` / `function` / `bigint` / `NaN`
21
+ */
22
+ declare function describeNonJsonValue(value: unknown): string;
23
+ /**
24
+ * 校验值是否为 JSON 安全类型;遇到非法值 / 循环引用立即抛 `TypeError`
25
+ *
26
+ * 允许:string / number(不含 NaN/Infinity)/ boolean / null / plain object / array
27
+ * 禁止:undefined / bigint / symbol / function / Set / Map / Date / RegExp / class 实例 /
28
+ * TypedArray / WeakMap / WeakSet / 循环引用 等
29
+ *
30
+ * `seen` 仅跟踪当前路径上访问过的容器(递归回溯时 `delete`),保证「同一兄弟节点的相同
31
+ * 引用」不会被误判为环
32
+ *
33
+ * @param subject 错误信息中的来源描述(如 `'getValue() result'` / `'actions.replace(next)'` / `'draft'`)
34
+ */
35
+ declare function assertJsonSafe(value: unknown, path: readonly PropertyKey[], seen: WeakSet<object>, subject: string): void;
36
+ /**
37
+ * 顶层数组运行时拒绝(fail-fast)
38
+ *
39
+ * 类型层已通过 `LockDataValueShape<T> = T extends readonly unknown[] ? never : T` 排除,
40
+ * 本函数仅作类型擦除路径下的最后一道防线 —— 抛 `InvalidOptionsError`
41
+ *
42
+ * @param value 待检查的值
43
+ * @param subject 错误信息中的来源描述(如 `'getValue() result'` / `'actions.replace(next)'`)
44
+ */
45
+ declare function assertNotTopLevelArray(value: unknown, subject: string): void;
46
+ /**
47
+ * JSON 拷贝隔离:把任意 JSON 安全的值深拷贝为全新引用
48
+ *
49
+ * 调用方必须保证 input 已通过 `assertJsonSafe` —— 本函数不做校验,直接 `JSON.parse(JSON.stringify(...))`
50
+ *
51
+ * 用途:
52
+ * - `entry.dataRef.current = cloneByJson(getValue 返回值)`:getValue 与内部状态隔离
53
+ * - `entry.dataRef.current = cloneByJson(committedNext)`:commit 与 draft 隔离
54
+ * - `actions.snapshot() = cloneByJson(entry.dataRef.current)`:调用方与内部状态隔离
55
+ * - `commitEvent.snapshot = cloneByJson(entry.dataRef.current)`:listener 与内部状态隔离
56
+ */
57
+ declare function cloneByJson<T>(value: T): T;
58
+ /**
59
+ * 入口便捷封装:组合 `assertNotTopLevelArray` + `assertJsonSafe`
60
+ *
61
+ * 用于 getValue / actions.replace 等"外部入参"边界的统一 fail-fast:
62
+ * 1. 顶层数组判定(双重 fail-fast 的运行时一道)
63
+ * 2. 整体 JSON 安全校验
64
+ *
65
+ * 同步链路抛 `InvalidOptionsError`(顶层数组)/ `TypeError`(其他非 JSON-safe),
66
+ * 调用方拿到错误后应原样向上抛
67
+ */
68
+ declare function assertJsonSafeInput(value: unknown, subject: string): void;
69
+ export { assertJsonSafe, assertJsonSafeInput, assertNotTopLevelArray, cloneByJson, describeNonJsonValue };
@@ -0,0 +1 @@
1
+ import{throwError as e}from"../../throw-error/index.js";import{ERROR_FN_NAME as t}from"../constants.js";import{InvalidOptionsError as r}from"../errors/index.js";function n(e){if(0===e.length)return"<root>";let t="";for(let r=0;r<e.length;r++){let n=e[r];if("number"==typeof n||"string"==typeof n&&/^\d+$/u.test(n)){t+=`[${String(n)}]`;continue}t+=0===r?String(n):`.${String(n)}`}return t}function o(e){if(void 0===e)return"undefined";if("number"==typeof e){if(Number.isNaN(e))return"NaN";if(!Number.isFinite(e))return e>0?"Infinity":"-Infinity"}let t=typeof e;if("object"!==t)return t;if(null===e)return"null";let r=Object.prototype.toString.call(e).slice(8,-1);if("Object"!==r)return r;let n=e.constructor;return n&&n!==Object&&"string"==typeof n.name&&n.name.length>0?`class instance (${n.name})`:"non-plain object"}function s(r,i,l,a){let u;if(null===r)return;void 0===r&&e(t,`${a} only supports JSON-safe values, got "undefined" at "${n(i)}" (use "null" instead)`,TypeError);let f=typeof r;if("string"===f||"boolean"===f)return;if("number"===f){Number.isFinite(r)||e(t,`${a} only supports JSON-safe values, got "${o(r)}" at "${n(i)}"`,TypeError);return}if("object"!==f&&e(t,`${a} only supports JSON-safe values, got "${o(r)}" at "${n(i)}"`,TypeError),l.has(r)&&e(t,`${a} detected cyclic reference at "${n(i)}"`,TypeError),Array.isArray(r)){l.add(r);for(let e=0;e<r.length;e++)s(r[e],[...i,e],l,a);l.delete(r);return}(u=Object.getPrototypeOf(r))!==Object.prototype&&null!==u&&e(t,`${a} only supports JSON-safe values (plain object / array / string / number / boolean / null), got "${o(r)}" at "${n(i)}"`,TypeError),l.add(r),Object.getOwnPropertySymbols(r).length>0&&e(t,`${a} only supports JSON-safe values, got symbol-keyed property at "${n(i)}"`,TypeError);let p=Object.keys(r);for(let e=0;e<p.length;e++){let t=p[e];s(r[t],[...i,t],l,a)}l.delete(r)}function i(n,o){Array.isArray(n)&&e(t,`${o} must not return an array; lockData rejects top-level arrays (wrap in object {} instead)`,r)}function l(e){return JSON.parse(JSON.stringify(e))}function a(e,t){i(e,t),s(e,[],new WeakSet,t)}export{s as assertJsonSafe,a as assertJsonSafeInput,i as assertNotTopLevelArray,l as cloneByJson,o as describeNonJsonValue};
@@ -2,9 +2,9 @@ type Logger = {
2
2
  [K in keyof Omit<Console, 'table'> as Console[K] extends (...args: any[]) => any ? K : never]: Console[K] extends (...args: [any, ...infer AS]) => infer R ? (fnName: string, ...args: AS) => R : never;
3
3
  };
4
4
  declare global {
5
- var $$lingshu$$: {
5
+ var $$lingshu$$: Partial<{
6
6
  disableLogger: boolean;
7
- };
7
+ }>;
8
8
  }
9
9
  export declare const logger: Logger;
10
10
  export {};
@@ -1,10 +1 @@
1
- const logger = new Proxy(console, {
2
- get (target, prop, receiver) {
3
- if ((globalThis.$$lingshu$$ || {}).disableLogger) return ()=>void 0;
4
- const oldLog = Reflect.get(target, prop, receiver).bind(console);
5
- return (fnName, ...args)=>{
6
- oldLog(`[@cmtlyt/lingshu-toolkit#${fnName}]:`, ...args);
7
- };
8
- }
9
- });
10
- export { logger };
1
+ let e=new Proxy(console,{get(e,l,o){if((globalThis.$$lingshu$$||{}).disableLogger)return()=>void 0;let t=Reflect.get(e,l,o).bind(console);return(e,...l)=>{t(`[@cmtlyt/lingshu-toolkit#${e}]:`,...l)}}});export{e as logger};
@@ -0,0 +1,45 @@
1
+ import type { PriorityQueueOptions } from './types';
2
+ declare class PriorityQueue<T> {
3
+ private readonly heap;
4
+ private readonly itemSet;
5
+ private readonly compare;
6
+ private readonly allowDuplicate;
7
+ private insertCounter;
8
+ constructor(options?: PriorityQueueOptions<T>);
9
+ private swapItems;
10
+ private heapifyUp;
11
+ private heapifyDown;
12
+ private isDuplicate;
13
+ enqueue(item: T): boolean;
14
+ enqueueMany(items: T[]): boolean[];
15
+ dequeue(): T | undefined;
16
+ peek(): T | undefined;
17
+ size(): number;
18
+ isEmpty(): boolean;
19
+ clear(): void;
20
+ /**
21
+ * 返回队列中所有元素的有序数组副本
22
+ *
23
+ * @description
24
+ * 该方法返回一个新数组,包含队列中的所有元素,按照以下顺序排列:
25
+ * 1. 优先级从小到大(根据 compare 函数)
26
+ * 2. 相同优先级的元素按照插入顺序(FIFO)
27
+ *
28
+ * 注意:返回的是数组副本,修改返回的数组不会影响原队列
29
+ *
30
+ * @returns 按优先级和插入顺序排序的元素数组
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const queue = priorityQueue<number>();
35
+ * queue.enqueue(3);
36
+ * queue.enqueue(1);
37
+ * queue.enqueue(2);
38
+ *
39
+ * console.log(queue.toArray()); // [1, 2, 3]
40
+ * ```
41
+ */
42
+ toArray(): T[];
43
+ }
44
+ declare function priorityQueue<T>(options?: PriorityQueueOptions<T>): PriorityQueue<T>;
45
+ export { priorityQueue };
@@ -0,0 +1 @@
1
+ import{$dt as e,$t as t,dataHandler as i}from"../data-handler/index.js";import{logger as h}from"../logger/index.js";import{tryCall as r}from"../try-call/index.js";import{defaultCompare as s,getLeftChildIndex as a,getParentIndex as p,getRightChildIndex as n,updateSmallestIndex as l}from"./utils.js";let o=e({compare:t.function(()=>s),allowDuplicate:t.boolean(!1)});class u{heap=[];itemSet=new Set;compare;allowDuplicate;insertCounter=0;constructor(e={}){let{compare:t,allowDuplicate:h}=i(e||{},o,{unwrap:!0});this.compare=t,this.allowDuplicate=h}swapItems(e,t){[this.heap[e],this.heap[t]]=[this.heap[t],this.heap[e]]}heapifyUp(e){let t=e;for(;t>0;){let e=p(t),i=this.heap[t],h=this.heap[e];if(0>this.compare(i.item,h.item))this.swapItems(t,e),t=e;else break}}heapifyDown(e){let t=e,i=this.heap.length;for(;t<i;){let e=a(t),h=n(t),r=t;if(r=l(e,r,i,this.heap,this.compare),(r=l(h,r,i,this.heap,this.compare))===t)break;this.swapItems(t,r),t=r}}isDuplicate(e){return!this.allowDuplicate&&this.itemSet.has(e)}enqueue(e){if(this.isDuplicate(e)){let t=r(()=>"object"==typeof e&&null!==e?JSON.stringify(e):String(e),()=>Object.prototype.toString.call(e));return h.warn("PriorityQueue.enqueue",`Duplicate item detected: ${t}`),!1}let t={item:e,insertOrder:this.insertCounter++};return this.allowDuplicate||this.itemSet.add(e),this.heap.push(t),this.heapifyUp(this.heap.length-1),!0}enqueueMany(e){return e.map(e=>this.enqueue(e))}dequeue(){let e;if(0!==this.heap.length)return 1===this.heap.length?e=this.heap.pop().item:(e=this.heap[0].item,this.heap[0]=this.heap.pop(),this.heapifyDown(0)),this.itemSet.delete(e),e}peek(){if(0!==this.heap.length)return this.heap[0].item}size(){return this.heap.length}isEmpty(){return 0===this.heap.length}clear(){this.heap.length=0,this.itemSet.clear(),this.insertCounter=0}toArray(){let e=[...this.heap];return e.sort((e,t)=>{let i=this.compare(e.item,t.item);return 0!==i?i:e.insertOrder-t.insertOrder}),e.map(e=>e.item)}}function m(e){return new u(e)}export{m as priorityQueue};
@@ -0,0 +1,10 @@
1
+ type CompareFn<T> = (first: T, second: T) => number;
2
+ interface PriorityQueueOptions<T> {
3
+ compare?: CompareFn<T>;
4
+ allowDuplicate?: boolean;
5
+ }
6
+ interface HeapItem<T> {
7
+ item: T;
8
+ insertOrder: number;
9
+ }
10
+ export type { CompareFn, HeapItem, PriorityQueueOptions };
File without changes
@@ -0,0 +1,7 @@
1
+ import type { CompareFn, HeapItem } from './types';
2
+ declare function defaultCompare<T>(left: T, right: T): number;
3
+ declare function getParentIndex(index: number): number;
4
+ declare function getLeftChildIndex(index: number): number;
5
+ declare function getRightChildIndex(index: number): number;
6
+ declare function updateSmallestIndex<T>(childIndex: number, smallestIndex: number, size: number, heap: HeapItem<T>[], compare: CompareFn<T>): number;
7
+ export { defaultCompare, getLeftChildIndex, getParentIndex, getRightChildIndex, updateSmallestIndex };
@@ -0,0 +1 @@
1
+ import{logger as e}from"../logger/index.js";import{getType as t}from"../utils/index.js";let r=new Set(["number","string","date"]);function n(n,i){return r.has(t(n))&&r.has(t(i))?n<i?-1:+(n>i):(e.warn("PriorityQueue",`Unsupported type: ${t(n)} ${t(i)}`),0)}function i(e){return Math.floor((e-1)/2)}function u(e){return 2*e+1}function o(e){return 2*e+2}function d(e,t,r,n,i){if(e>=r)return t;let u=i(n[e].item,n[t].item);return u<0||0===u&&n[e].insertOrder<n[t].insertOrder?e:t}export{n as defaultCompare,u as getLeftChildIndex,i as getParentIndex,o as getRightChildIndex,d as updateSmallestIndex};
@@ -1,3 +1,11 @@
1
- export declare function createError(fnName: string, message: string, ErrorClass?: ErrorConstructor): Error;
2
- export declare function throwError(fnName: string, message: string, ErrorClass?: ErrorConstructor): never;
3
- export declare function throwType(fnName: string, message: string): never;
1
+ interface ErrorOptions {
2
+ /** 原始错误(ES2022 Error.cause),便于错误链追踪 */
3
+ cause?: unknown;
4
+ }
5
+ declare function createError(fnName: string, message: string, ErrorClass?: ErrorConstructor, options?: ErrorOptions): Error;
6
+ declare function createError(fnName: string, message: string, options?: ErrorOptions): Error;
7
+ declare function throwError(fnName: string, message: string, ErrorClass?: ErrorConstructor, options?: ErrorOptions): never;
8
+ declare function throwError(fnName: string, message: string, options?: ErrorOptions): never;
9
+ declare function throwType(fnName: string, message: string, options?: ErrorOptions): never;
10
+ export type { ErrorOptions };
11
+ export { createError, throwError, throwType };
@@ -1,10 +1 @@
1
- function createError(fnName, message, ErrorClass = Error) {
2
- return new ErrorClass(`[@cmtlyt/lingshu-toolkit#${fnName}]: ${message}`);
3
- }
4
- function throwError(fnName, message, ErrorClass = Error) {
5
- throw createError(fnName, message, ErrorClass);
6
- }
7
- function throwType(fnName, message) {
8
- throwError(fnName, message, TypeError);
9
- }
10
- export { createError, throwError, throwType };
1
+ function r(o,t,e=Error,n){let c="function"==typeof e,u=c?e:Error,i=c?n:e,E=`[@cmtlyt/lingshu-toolkit#${o}]: ${t}`;return i&&"cause"in i?new u(E,{cause:i.cause}):new u(E)}function o(t,e,n=Error,c){throw r(t,e,n,c)}function t(r,t,e){o(r,t,TypeError,e)}export{r as createError,o as throwError,t as throwType};
@@ -9,7 +9,7 @@ type TryCallFinalArgs<R, E> = TryCallResultValue<R, E> | Error;
9
9
  * @param cb 回调函数
10
10
  * @param onError 错误处理函数
11
11
  */
12
- export declare function tryCallFunc<A extends any[], R, E = never>(cb: (...args: A) => R, onError?: ((err: any) => E) | null, onFinal?: (result: TryCallFinalArgs<R, E>) => void): (...args: A) => TryCallResult<R, E>;
12
+ declare function tryCallFunc<A extends any[], R, E = never>(cb: (...args: A) => R, onError?: ((err: any) => E) | null, onFinal?: (result: TryCallFinalArgs<R, E>) => void): (...args: A) => TryCallResult<R, E>;
13
13
  /**
14
14
  * 尝试调用函数
15
15
  *
@@ -18,5 +18,5 @@ export declare function tryCallFunc<A extends any[], R, E = never>(cb: (...args:
18
18
  * @param cb 回调函数
19
19
  * @param onError 错误处理函数
20
20
  */
21
- export declare function tryCall<R, E = never>(this: any, cb: () => R, onError?: ((err: any) => E) | null, onFinal?: (result: TryCallFinalArgs<R, E>) => void): TryCallResult<R, E>;
22
- export {};
21
+ declare function tryCall<R, E = never>(this: any, cb: () => R, onError?: ((err: any) => E) | null, onFinal?: (result: TryCallFinalArgs<R, E>) => void): TryCallResult<R, E>;
22
+ export { tryCall, tryCallFunc };
@@ -1,59 +1 @@
1
- import { throwType } from "../throw-error/index.js";
2
- import { isFunction, isPromiseLike } from "../utils/verify.js";
3
- const EMPTY = Symbol('EMPTY');
4
- function tryCallFunc(cb, onError, onFinal) {
5
- if (!isFunction(cb)) throwType('tryCallFunc', 'callback is not a function');
6
- const catchFn = (self, ctx, error)=>{
7
- if (isFunction(onError)) try {
8
- ctx.errorResult = Reflect.apply(onError, self, [
9
- error
10
- ]);
11
- } catch (err) {
12
- ctx.error = err;
13
- }
14
- else ctx.error = error;
15
- return ctx.errorResult;
16
- };
17
- const finallyFn = (self, ctx, result)=>{
18
- try {
19
- if (ctx.error !== EMPTY) throw ctx.error;
20
- } finally{
21
- if (isFunction(onFinal)) if (ctx.errorResult !== EMPTY) Reflect.apply(onFinal, self, [
22
- ctx.errorResult
23
- ]);
24
- else if (ctx.error !== EMPTY) Reflect.apply(onFinal, self, [
25
- ctx.error
26
- ]);
27
- else Reflect.apply(onFinal, self, [
28
- result
29
- ]);
30
- }
31
- };
32
- return function(...args) {
33
- const ctx = {
34
- oriResult: EMPTY,
35
- errorResult: EMPTY,
36
- error: EMPTY
37
- };
38
- const asyncFn = async ()=>{
39
- try {
40
- ctx.oriResult = Reflect.apply(cb, this, args);
41
- return ctx.oriResult;
42
- } catch (error) {
43
- return catchFn(this, ctx, error);
44
- }
45
- };
46
- const fnPromise = asyncFn().catch((error)=>catchFn(this, ctx, error));
47
- if (isPromiseLike(ctx.oriResult)) return fnPromise.then((result)=>{
48
- finallyFn(this, ctx, result);
49
- return result;
50
- });
51
- finallyFn(this, ctx, ctx.oriResult);
52
- return ctx.oriResult !== EMPTY ? ctx.oriResult : ctx.errorResult;
53
- };
54
- }
55
- function tryCall(cb, onError, onFinal) {
56
- if (!isFunction(cb)) throwType('tryCall', 'callback is not a function');
57
- return tryCallFunc(cb, onError, onFinal).call(this);
58
- }
59
- export { tryCall, tryCallFunc };
1
+ import{throwType as r}from"../throw-error/index.js";import{isFunction as t,isPromiseLike as e}from"../utils/verify.js";let l=Symbol("EMPTY");function o(o,i,n){t(o)||r("tryCallFunc","callback is not a function");let u=(r,e,l)=>{if(t(i))try{e.errorResult=Reflect.apply(i,r,[l])}catch(r){e.error=r}else e.error=l;return e.errorResult},s=(r,e,o)=>{try{if(e.error!==l)throw e.error}finally{t(n)&&Reflect.apply(n,r,e.error===l?[o]:[e.error])}};return function(...r){let t={oriResult:l,errorResult:l,error:l},i=(async()=>{try{return t.oriResult=Reflect.apply(o,this,r),t.oriResult}catch(r){return u(this,t,r)}})().catch(r=>u(this,t,r));if(e(t.oriResult))return i.then(r=>(s(this,t,r),r));let n=t.oriResult===l?t.errorResult:t.oriResult;return s(this,t,n),n}}function i(e,l,i){return t(e)||r("tryCall","callback is not a function"),o(e,l,i).call(this)}export{i as tryCall,o as tryCallFunc};
@@ -1,2 +1 @@
1
- export * from "./base.js";
2
- export * from "./pack.js";
1
+ export*from"./base.js";export*from"./pack.js";
@@ -1,7 +1,7 @@
1
1
  declare const __PACK__: unique symbol;
2
- export type Pack<T> = {
2
+ export interface Pack<T> {
3
3
  [__PACK__]: T;
4
- };
4
+ }
5
5
  export type Unpack<T extends Pack<any>> = T extends Pack<infer U> ? U : never;
6
6
  export type SafeUnpack<T> = T extends Pack<infer U> ? U : T;
7
7
  export type IsPack<T> = Pack<any> extends T ? true : false;