@zk-tech/bedrock 0.0.1

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 (390) hide show
  1. package/README.md +24 -0
  2. package/dist/array/index.cjs +22 -0
  3. package/dist/array/index.cjs.map +1 -0
  4. package/dist/array/index.d.cts +13 -0
  5. package/dist/array/index.d.ts +13 -0
  6. package/dist/array/index.js +19 -0
  7. package/dist/array/index.js.map +1 -0
  8. package/dist/assert/index.cjs +29 -0
  9. package/dist/assert/index.cjs.map +1 -0
  10. package/dist/assert/index.d.cts +25 -0
  11. package/dist/assert/index.d.ts +25 -0
  12. package/dist/assert/index.js +24 -0
  13. package/dist/assert/index.js.map +1 -0
  14. package/dist/async/index.cjs +746 -0
  15. package/dist/async/index.cjs.map +1 -0
  16. package/dist/async/index.d.cts +47 -0
  17. package/dist/async/index.d.ts +47 -0
  18. package/dist/async/index.js +738 -0
  19. package/dist/async/index.js.map +1 -0
  20. package/dist/barrier-316Xonfd.d.cts +18 -0
  21. package/dist/barrier-316Xonfd.d.ts +18 -0
  22. package/dist/byte/index.cjs +59 -0
  23. package/dist/byte/index.cjs.map +1 -0
  24. package/dist/byte/index.d.cts +12 -0
  25. package/dist/byte/index.d.ts +12 -0
  26. package/dist/byte/index.js +49 -0
  27. package/dist/byte/index.js.map +1 -0
  28. package/dist/cache/index.cjs +418 -0
  29. package/dist/cache/index.cjs.map +1 -0
  30. package/dist/cache/index.d.cts +40 -0
  31. package/dist/cache/index.d.ts +40 -0
  32. package/dist/cache/index.js +415 -0
  33. package/dist/cache/index.js.map +1 -0
  34. package/dist/cancellation-BIIv2UJm.d.cts +25 -0
  35. package/dist/cancellation-ClqPPsV1.d.ts +25 -0
  36. package/dist/context/index.cjs +59 -0
  37. package/dist/context/index.cjs.map +1 -0
  38. package/dist/context/index.d.cts +33 -0
  39. package/dist/context/index.d.ts +33 -0
  40. package/dist/context/index.js +51 -0
  41. package/dist/context/index.js.map +1 -0
  42. package/dist/di/index.cjs +1965 -0
  43. package/dist/di/index.cjs.map +1 -0
  44. package/dist/di/index.d.cts +140 -0
  45. package/dist/di/index.d.ts +140 -0
  46. package/dist/di/index.js +1949 -0
  47. package/dist/di/index.js.map +1 -0
  48. package/dist/disposable-t-B15Nu57y.d.ts +93 -0
  49. package/dist/disposable-t-CVsiyHPL.d.cts +93 -0
  50. package/dist/dispose/index.cjs +356 -0
  51. package/dist/dispose/index.cjs.map +1 -0
  52. package/dist/dispose/index.d.cts +26 -0
  53. package/dist/dispose/index.d.ts +26 -0
  54. package/dist/dispose/index.js +340 -0
  55. package/dist/dispose/index.js.map +1 -0
  56. package/dist/dispose-base-CAeXDpjg.d.cts +6 -0
  57. package/dist/dispose-base-CAeXDpjg.d.ts +6 -0
  58. package/dist/emitter-CAfCtSTg.d.cts +35 -0
  59. package/dist/emitter-DeM5mlEm.d.ts +35 -0
  60. package/dist/error/index.cjs +145 -0
  61. package/dist/error/index.cjs.map +1 -0
  62. package/dist/error/index.d.cts +45 -0
  63. package/dist/error/index.d.ts +45 -0
  64. package/dist/error/index.js +126 -0
  65. package/dist/error/index.js.map +1 -0
  66. package/dist/error-base-B4zaiJ5m.d.cts +32 -0
  67. package/dist/error-base-B4zaiJ5m.d.ts +32 -0
  68. package/dist/event/index.cjs +550 -0
  69. package/dist/event/index.cjs.map +1 -0
  70. package/dist/event/index.d.cts +139 -0
  71. package/dist/event/index.d.ts +139 -0
  72. package/dist/event/index.js +538 -0
  73. package/dist/event/index.js.map +1 -0
  74. package/dist/function/index.cjs +132 -0
  75. package/dist/function/index.cjs.map +1 -0
  76. package/dist/function/index.d.cts +26 -0
  77. package/dist/function/index.d.ts +26 -0
  78. package/dist/function/index.js +129 -0
  79. package/dist/function/index.js.map +1 -0
  80. package/dist/graph-BGbNOniY.d.cts +23 -0
  81. package/dist/graph-BGbNOniY.d.ts +23 -0
  82. package/dist/hash/index.cjs +54 -0
  83. package/dist/hash/index.cjs.map +1 -0
  84. package/dist/hash/index.d.cts +5 -0
  85. package/dist/hash/index.d.ts +5 -0
  86. package/dist/hash/index.js +50 -0
  87. package/dist/hash/index.js.map +1 -0
  88. package/dist/instantiation-service.interface-CVFMBUUD.d.cts +78 -0
  89. package/dist/instantiation-service.interface-CVFMBUUD.d.ts +78 -0
  90. package/dist/json/index.cjs +28 -0
  91. package/dist/json/index.cjs.map +1 -0
  92. package/dist/json/index.d.cts +8 -0
  93. package/dist/json/index.d.ts +8 -0
  94. package/dist/json/index.js +26 -0
  95. package/dist/json/index.js.map +1 -0
  96. package/dist/launch/index.cjs +213 -0
  97. package/dist/launch/index.cjs.map +1 -0
  98. package/dist/launch/index.d.cts +46 -0
  99. package/dist/launch/index.d.ts +46 -0
  100. package/dist/launch/index.js +211 -0
  101. package/dist/launch/index.js.map +1 -0
  102. package/dist/linked-list-CUkue5DZ.d.cts +24 -0
  103. package/dist/linked-list-CUkue5DZ.d.ts +24 -0
  104. package/dist/lock/index.cjs +662 -0
  105. package/dist/lock/index.cjs.map +1 -0
  106. package/dist/lock/index.d.cts +145 -0
  107. package/dist/lock/index.d.ts +145 -0
  108. package/dist/lock/index.js +656 -0
  109. package/dist/lock/index.js.map +1 -0
  110. package/dist/lodash-es/index.cjs +14 -0
  111. package/dist/lodash-es/index.cjs.map +1 -0
  112. package/dist/lodash-es/index.d.cts +1 -0
  113. package/dist/lodash-es/index.d.ts +1 -0
  114. package/dist/lodash-es/index.js +3 -0
  115. package/dist/lodash-es/index.js.map +1 -0
  116. package/dist/math/index.cjs +161 -0
  117. package/dist/math/index.cjs.map +1 -0
  118. package/dist/math/index.d.cts +76 -0
  119. package/dist/math/index.d.ts +76 -0
  120. package/dist/math/index.js +156 -0
  121. package/dist/math/index.js.map +1 -0
  122. package/dist/network/index.cjs +91 -0
  123. package/dist/network/index.cjs.map +1 -0
  124. package/dist/network/index.d.cts +62 -0
  125. package/dist/network/index.d.ts +62 -0
  126. package/dist/network/index.js +82 -0
  127. package/dist/network/index.js.map +1 -0
  128. package/dist/objects/index.cjs +80 -0
  129. package/dist/objects/index.cjs.map +1 -0
  130. package/dist/objects/index.d.cts +11 -0
  131. package/dist/objects/index.d.ts +11 -0
  132. package/dist/objects/index.js +77 -0
  133. package/dist/objects/index.js.map +1 -0
  134. package/dist/platform/index.cjs +62 -0
  135. package/dist/platform/index.cjs.map +1 -0
  136. package/dist/platform/index.d.cts +21 -0
  137. package/dist/platform/index.d.ts +21 -0
  138. package/dist/platform/index.js +48 -0
  139. package/dist/platform/index.js.map +1 -0
  140. package/dist/promise/index.cjs +639 -0
  141. package/dist/promise/index.cjs.map +1 -0
  142. package/dist/promise/index.d.cts +63 -0
  143. package/dist/promise/index.d.ts +63 -0
  144. package/dist/promise/index.js +633 -0
  145. package/dist/promise/index.js.map +1 -0
  146. package/dist/scheduler/index.cjs +599 -0
  147. package/dist/scheduler/index.cjs.map +1 -0
  148. package/dist/scheduler/index.d.cts +57 -0
  149. package/dist/scheduler/index.d.ts +57 -0
  150. package/dist/scheduler/index.js +594 -0
  151. package/dist/scheduler/index.js.map +1 -0
  152. package/dist/sprintf/index.cjs +101 -0
  153. package/dist/sprintf/index.cjs.map +1 -0
  154. package/dist/sprintf/index.d.cts +3 -0
  155. package/dist/sprintf/index.d.ts +3 -0
  156. package/dist/sprintf/index.js +99 -0
  157. package/dist/sprintf/index.js.map +1 -0
  158. package/dist/structure/index.cjs +300 -0
  159. package/dist/structure/index.cjs.map +1 -0
  160. package/dist/structure/index.d.cts +21 -0
  161. package/dist/structure/index.d.ts +21 -0
  162. package/dist/structure/index.js +296 -0
  163. package/dist/structure/index.js.map +1 -0
  164. package/dist/type/index.cjs +4 -0
  165. package/dist/type/index.cjs.map +1 -0
  166. package/dist/type/index.d.cts +20 -0
  167. package/dist/type/index.d.ts +20 -0
  168. package/dist/type/index.js +3 -0
  169. package/dist/type/index.js.map +1 -0
  170. package/dist/undo-redo-stack/index.cjs +545 -0
  171. package/dist/undo-redo-stack/index.cjs.map +1 -0
  172. package/dist/undo-redo-stack/index.d.cts +130 -0
  173. package/dist/undo-redo-stack/index.d.ts +130 -0
  174. package/dist/undo-redo-stack/index.js +542 -0
  175. package/dist/undo-redo-stack/index.js.map +1 -0
  176. package/dist/uuid/index.cjs +67 -0
  177. package/dist/uuid/index.cjs.map +1 -0
  178. package/dist/uuid/index.d.cts +17 -0
  179. package/dist/uuid/index.d.ts +17 -0
  180. package/dist/uuid/index.js +61 -0
  181. package/dist/uuid/index.js.map +1 -0
  182. package/dist/worker/index.cjs +271 -0
  183. package/dist/worker/index.cjs.map +1 -0
  184. package/dist/worker/index.d.cts +66 -0
  185. package/dist/worker/index.d.ts +66 -0
  186. package/dist/worker/index.js +267 -0
  187. package/dist/worker/index.js.map +1 -0
  188. package/package.json +285 -0
  189. package/src/_internal/logger.ts +59 -0
  190. package/src/array/array.test.ts +35 -0
  191. package/src/array/array.ts +25 -0
  192. package/src/array/index.ts +1 -0
  193. package/src/assert/assert.test.ts +86 -0
  194. package/src/assert/assert.ts +42 -0
  195. package/src/assert/index.ts +2 -0
  196. package/src/async/barrier.test.ts +90 -0
  197. package/src/async/barrier.ts +58 -0
  198. package/src/async/cancellation.test.ts +85 -0
  199. package/src/async/cancellation.ts +193 -0
  200. package/src/async/index.ts +18 -0
  201. package/src/async/queue/queue.test.ts +70 -0
  202. package/src/async/queue/queue.ts +56 -0
  203. package/src/async/queue/task.test.ts +155 -0
  204. package/src/async/queue/task.ts +67 -0
  205. package/src/async/utils.test.ts +28 -0
  206. package/src/async/utils.ts +8 -0
  207. package/src/async/wait.ts +9 -0
  208. package/src/byte/format.test.ts +64 -0
  209. package/src/byte/format.ts +44 -0
  210. package/src/byte/index.ts +2 -0
  211. package/src/byte/node_modules/.vitest/results.json +1 -0
  212. package/src/byte/var.ts +11 -0
  213. package/src/cache/index.ts +2 -0
  214. package/src/cache/lru-with-timeout.test.ts +88 -0
  215. package/src/cache/lru-with-timeout.ts +85 -0
  216. package/src/cache/lru.test.ts +56 -0
  217. package/src/cache/lru.ts +59 -0
  218. package/src/context/context.test.ts +17 -0
  219. package/src/context/context.ts +60 -0
  220. package/src/context/index.ts +8 -0
  221. package/src/di/base.ts +73 -0
  222. package/src/di/container-service.test.ts +179 -0
  223. package/src/di/context.web.tsx +41 -0
  224. package/src/di/descriptor.ts +31 -0
  225. package/src/di/idle-value.test.ts +73 -0
  226. package/src/di/idle-value.ts +63 -0
  227. package/src/di/index.common.ts +32 -0
  228. package/src/di/index.ts +2 -0
  229. package/src/di/instantiation-service.interface.ts +46 -0
  230. package/src/di/instantiation-service.test.ts +337 -0
  231. package/src/di/instantiation-service.ts +468 -0
  232. package/src/di/lazy/foo.mock.ts +28 -0
  233. package/src/di/lazy/idle-load.ts +39 -0
  234. package/src/di/lazy/index.ts +4 -0
  235. package/src/di/lazy/lazy-service.test.ts +65 -0
  236. package/src/di/lazy/lazy-service.ts +71 -0
  237. package/src/di/lazy/type.ts +5 -0
  238. package/src/di/node_modules/.vitest/results.json +1 -0
  239. package/src/di/proxy-builder.test.ts +45 -0
  240. package/src/di/proxy-builder.ts +38 -0
  241. package/src/di/service-collection.test.ts +27 -0
  242. package/src/di/service-collection.ts +46 -0
  243. package/src/di/service-ownership-collection.test.ts +39 -0
  244. package/src/di/service-ownership-collection.ts +38 -0
  245. package/src/di/service-registry.test.ts +66 -0
  246. package/src/di/service-registry.ts +99 -0
  247. package/src/di/trace.ts +85 -0
  248. package/src/dispose/disposable-store.test.ts +57 -0
  249. package/src/dispose/disposable-store.ts +80 -0
  250. package/src/dispose/disposable-t.test.ts +123 -0
  251. package/src/dispose/disposable-t.ts +238 -0
  252. package/src/dispose/disposable-utils.test.ts +15 -0
  253. package/src/dispose/disposable-utils.ts +28 -0
  254. package/src/dispose/dispose-base.ts +9 -0
  255. package/src/dispose/index.ts +34 -0
  256. package/src/dispose/logger.test.ts +65 -0
  257. package/src/dispose/logger.ts +39 -0
  258. package/src/dispose/timer.test.ts +30 -0
  259. package/src/dispose/timer.ts +16 -0
  260. package/src/dispose/tracker.test.ts +51 -0
  261. package/src/dispose/tracker.ts +105 -0
  262. package/src/error/error-base.ts +45 -0
  263. package/src/error/error-code.ts +39 -0
  264. package/src/error/error-const.test.ts +30 -0
  265. package/src/error/error-const.ts +16 -0
  266. package/src/error/error-or.test.ts +44 -0
  267. package/src/error/error-or.ts +2 -0
  268. package/src/error/error-t.test.ts +116 -0
  269. package/src/error/error-t.ts +100 -0
  270. package/src/error/index.ts +24 -0
  271. package/src/error/node_modules/.vitest/results.json +1 -0
  272. package/src/event/disposable-linked-list.ts +29 -0
  273. package/src/event/emitter.test.ts +191 -0
  274. package/src/event/emitter.ts +162 -0
  275. package/src/event/error-handler.ts +22 -0
  276. package/src/event/index.ts +34 -0
  277. package/src/event/once.ts +29 -0
  278. package/src/event/phase-emitter.test.ts +212 -0
  279. package/src/event/phase-emitter.ts +209 -0
  280. package/src/event/shortcut-event-utils.ts +33 -0
  281. package/src/event/utils.ts +6 -0
  282. package/src/event/when.ts +40 -0
  283. package/src/function/debounce.test.ts +274 -0
  284. package/src/function/debounce.ts +168 -0
  285. package/src/function/index.ts +2 -0
  286. package/src/function/node_modules/.vitest/results.json +1 -0
  287. package/src/function/throttle.test.ts +179 -0
  288. package/src/function/throttle.ts +26 -0
  289. package/src/hash/hash-t.test.ts +100 -0
  290. package/src/hash/hash-t.ts +51 -0
  291. package/src/hash/index.ts +3 -0
  292. package/src/json/index.ts +1 -0
  293. package/src/json/node_modules/.vitest/results.json +1 -0
  294. package/src/json/parse.ts +19 -0
  295. package/src/launch/abstract-job.ts +45 -0
  296. package/src/launch/cost-recorder.ts +22 -0
  297. package/src/launch/index.ts +2 -0
  298. package/src/launch/job-scheduler.test.ts +122 -0
  299. package/src/launch/job-scheduler.ts +118 -0
  300. package/src/launch/node_modules/.vitest/deps/_metadata.json +8 -0
  301. package/src/launch/node_modules/.vitest/deps/package.json +3 -0
  302. package/src/launch/node_modules/.vitest/results.json +1 -0
  303. package/src/lock/README.md +11 -0
  304. package/src/lock/capability.test.ts +110 -0
  305. package/src/lock/capability.ts +89 -0
  306. package/src/lock/index.ts +15 -0
  307. package/src/lock/node_modules/.vitest/results.json +1 -0
  308. package/src/lock/semaphore.ts +21 -0
  309. package/src/lock/shared-mutex.test.ts +537 -0
  310. package/src/lock/shared-mutex.ts +242 -0
  311. package/src/lock/utils.test.ts +165 -0
  312. package/src/lock/utils.ts +135 -0
  313. package/src/lodash-es/index.ts +1 -0
  314. package/src/math/degree.ts +16 -0
  315. package/src/math/index.ts +7 -0
  316. package/src/math/math.test.ts +40 -0
  317. package/src/math/math.ts +64 -0
  318. package/src/math/node_modules/.vitest/results.json +1 -0
  319. package/src/math/vector.test.ts +73 -0
  320. package/src/math/vector.ts +114 -0
  321. package/src/network/client.interface.ts +104 -0
  322. package/src/network/client.web.ts +24 -0
  323. package/src/network/index.common.ts +10 -0
  324. package/src/network/index.ts +2 -0
  325. package/src/network/plugins/retry.ts +98 -0
  326. package/src/objects/deep-clone.test.ts +40 -0
  327. package/src/objects/deep-clone.ts +13 -0
  328. package/src/objects/deep-equal.test.ts +86 -0
  329. package/src/objects/deep-equal.ts +60 -0
  330. package/src/objects/index.ts +4 -0
  331. package/src/platform/index.ts +64 -0
  332. package/src/promise/index.ts +16 -0
  333. package/src/promise/promise.test.ts +254 -0
  334. package/src/promise/promise.ts +212 -0
  335. package/src/scheduler/callback-token.ts +31 -0
  336. package/src/scheduler/core/actuator-args.test.ts +47 -0
  337. package/src/scheduler/core/actuator.test.ts +82 -0
  338. package/src/scheduler/core/actuator.ts +58 -0
  339. package/src/scheduler/core/chunk-scheduler.test.ts +54 -0
  340. package/src/scheduler/core/chunk-scheduler.ts +28 -0
  341. package/src/scheduler/core/node_modules/.vitest/results.json +1 -0
  342. package/src/scheduler/core/scheduler.test.ts +328 -0
  343. package/src/scheduler/core/scheduler.ts +172 -0
  344. package/src/scheduler/core/task-queue.test.ts +78 -0
  345. package/src/scheduler/core/task-queue.ts +44 -0
  346. package/src/scheduler/core/task.test.ts +34 -0
  347. package/src/scheduler/core/task.ts +52 -0
  348. package/src/scheduler/core/utils.ts +48 -0
  349. package/src/scheduler/executor/abstract-executor.test.ts +44 -0
  350. package/src/scheduler/executor/abstract-executor.ts +38 -0
  351. package/src/scheduler/executor/executor.interface.ts +39 -0
  352. package/src/scheduler/executor/idle-callback-executor.test.ts +70 -0
  353. package/src/scheduler/executor/idle-callback-executor.ts +98 -0
  354. package/src/scheduler/executor/make-executor.ts +18 -0
  355. package/src/scheduler/executor/post-message-executor.test.ts +66 -0
  356. package/src/scheduler/executor/post-message-executor.ts +52 -0
  357. package/src/scheduler/index.ts +15 -0
  358. package/src/scheduler/lv-scheduler-callback.ts +19 -0
  359. package/src/scheduler/lv-scheduler-config.ts +17 -0
  360. package/src/scheduler/type.ts +48 -0
  361. package/src/sprintf/index.ts +2 -0
  362. package/src/sprintf/sprintf.test.ts +95 -0
  363. package/src/sprintf/sprintf.ts +97 -0
  364. package/src/structure/graph.test.ts +181 -0
  365. package/src/structure/graph.ts +105 -0
  366. package/src/structure/index.ts +8 -0
  367. package/src/structure/linked-list.test.ts +74 -0
  368. package/src/structure/linked-list.ts +145 -0
  369. package/src/structure/min-heap.test.ts +71 -0
  370. package/src/structure/min-heap.ts +91 -0
  371. package/src/type/REAME.md +2 -0
  372. package/src/type/distributive-omit.interface.ts +4 -0
  373. package/src/type/index.ts +3 -0
  374. package/src/type/object-key-paths.interface.ts +40 -0
  375. package/src/undo-redo-stack/README.md +61 -0
  376. package/src/undo-redo-stack/action-stack.test.ts +330 -0
  377. package/src/undo-redo-stack/action-stack.ts +150 -0
  378. package/src/undo-redo-stack/element.ts +4 -0
  379. package/src/undo-redo-stack/index.ts +7 -0
  380. package/src/undo-redo-stack/state-stack.test.ts +118 -0
  381. package/src/undo-redo-stack/state-stack.ts +133 -0
  382. package/src/uuid/index.ts +7 -0
  383. package/src/uuid/uuid.ts +86 -0
  384. package/src/worker/cors-worker.ts +38 -0
  385. package/src/worker/index.ts +4 -0
  386. package/src/worker/node_modules/.vitest/results.json +1 -0
  387. package/src/worker/promise-worker-main-thread.test.ts +91 -0
  388. package/src/worker/promise-worker-main-thread.ts +76 -0
  389. package/src/worker/promise-worker-worker-thread.ts +64 -0
  390. package/src/worker/promise-worker.interface.ts +15 -0
@@ -0,0 +1,71 @@
1
+ import { MinHeap } from './min-heap';
2
+
3
+ describe('MinHeap', () => {
4
+ let heap: MinHeap<number>;
5
+
6
+ beforeEach(() => {
7
+ heap = new MinHeap();
8
+ });
9
+
10
+ test('insert adds a value and sifts it up the heap', () => {
11
+ heap.insert(2);
12
+ expect(heap.peek()).toEqual(2);
13
+
14
+ heap.insert(3);
15
+ expect(heap.peek()).toEqual(2);
16
+
17
+ heap.insert(1);
18
+ expect(heap.peek()).toEqual(1);
19
+ });
20
+
21
+ test('peek returns the minimum value without removing it', () => {
22
+ expect(heap.peek()).toBeNull();
23
+
24
+ heap.insert(1);
25
+ expect(heap.peek()).toEqual(1);
26
+
27
+ heap.insert(0);
28
+ expect(heap.peek()).toEqual(0);
29
+
30
+ heap.remove();
31
+ expect(heap.peek()).toEqual(1);
32
+ });
33
+
34
+ test('remove extracts the minimum value and returns it', () => {
35
+ expect(heap.remove()).toBeNull();
36
+
37
+ heap.insert(2);
38
+ heap.insert(3);
39
+ heap.insert(1);
40
+
41
+ expect(heap.remove()).toBe(1);
42
+ expect(heap.remove()).toBe(2);
43
+ expect(heap.remove()).toBe(3);
44
+ expect(heap.remove()).toBeNull();
45
+ });
46
+
47
+ test('size returns the number of elements in the heap', () => {
48
+ expect(heap.size()).toBe(0);
49
+
50
+ heap.insert(2);
51
+ heap.insert(3);
52
+ expect(heap.size()).toBe(2);
53
+
54
+ heap.remove();
55
+ expect(heap.size()).toBe(1);
56
+ });
57
+
58
+ test('heap maintains the heap property on inserts and removes', () => {
59
+ heap.insert(3);
60
+ heap.insert(4);
61
+ heap.insert(5);
62
+ heap.insert(1);
63
+ heap.insert(2);
64
+
65
+ expect(heap.remove()).toEqual(1);
66
+ expect(heap.remove()).toEqual(2);
67
+ expect(heap.remove()).toEqual(3);
68
+ expect(heap.remove()).toEqual(4);
69
+ expect(heap.remove()).toEqual(5);
70
+ });
71
+ });
@@ -0,0 +1,91 @@
1
+ export class MinHeap<T> {
2
+ private readonly _heap: T[] = [];
3
+ private readonly _compare: (a: T, b: T) => number;
4
+
5
+ constructor(compareFunction?: (a: T, b: T) => number) {
6
+ if (compareFunction) {
7
+ this._compare = compareFunction;
8
+ } else {
9
+ this._compare = (a, b) => {
10
+ if (a < b) return -1;
11
+ if (a > b) return 1;
12
+ return 0;
13
+ };
14
+ }
15
+ }
16
+
17
+ public insert(value: T): void {
18
+ this._heap.push(value);
19
+ this._siftUp();
20
+ }
21
+
22
+ public peek(): T | null {
23
+ return this._heap.length > 0 ? this._heap[0] : null;
24
+ }
25
+
26
+ public remove(): T | null {
27
+ if (this._heap.length === 0) return null;
28
+ if (this._heap.length === 1) return this._heap.pop()!;
29
+
30
+ const item = this._heap[0];
31
+ this._heap[0] = this._heap.pop()!;
32
+ this._siftDown();
33
+ return item;
34
+ }
35
+
36
+ public size(): number {
37
+ return this._heap.length;
38
+ }
39
+
40
+ public clear(): void {
41
+ this._heap.length = 0;
42
+ }
43
+
44
+ private _getLeftChildIndex(parentIndex: number): number {
45
+ return 2 * parentIndex + 1;
46
+ }
47
+
48
+ private _getRightChildIndex(parentIndex: number): number {
49
+ return 2 * parentIndex + 2;
50
+ }
51
+
52
+ private _getParentIndex(childIndex: number): number {
53
+ return Math.floor((childIndex - 1) / 2);
54
+ }
55
+
56
+ private _swap(indexOne: number, indexTwo: number): void {
57
+ [this._heap[indexOne], this._heap[indexTwo]] = [this._heap[indexTwo], this._heap[indexOne]];
58
+ }
59
+
60
+ private _siftUp(): void {
61
+ let index = this._heap.length - 1;
62
+ while (index > 0 && this._compare(this._heap[this._getParentIndex(index)], this._heap[index]) > 0) {
63
+ const parentIndex = this._getParentIndex(index);
64
+ this._swap(index, parentIndex);
65
+ index = parentIndex;
66
+ }
67
+ }
68
+
69
+ private _siftDown(): void {
70
+ let index = 0;
71
+ let smallerChildIndex = this._getLeftChildIndex(index);
72
+
73
+ while (smallerChildIndex < this._heap.length) {
74
+ const rightChildIndex = this._getRightChildIndex(index);
75
+ if (
76
+ rightChildIndex < this._heap.length &&
77
+ this._compare(this._heap[rightChildIndex], this._heap[smallerChildIndex]) < 0
78
+ ) {
79
+ smallerChildIndex = rightChildIndex;
80
+ }
81
+
82
+ if (this._compare(this._heap[index], this._heap[smallerChildIndex]) <= 0) {
83
+ break;
84
+ }
85
+
86
+ this._swap(index, smallerChildIndex);
87
+ index = smallerChildIndex;
88
+ smallerChildIndex = this._getLeftChildIndex(index);
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,2 @@
1
+ # Typescript typing
2
+ 定义项目内用到的 typescript 高级类型
@@ -0,0 +1,4 @@
1
+ // Typescript 提供的 Omit 函数会导致联合结构丢失,额外包装实现
2
+ // https://stackoverflow.com/questions/57103834/typescript-omit-a-property-from-all-interfaces-in-a-union-but-keep-the-union-s/57103940#57103940
3
+
4
+ export type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
@@ -0,0 +1,3 @@
1
+ export type { DistributiveOmit } from './distributive-omit.interface';
2
+
3
+ export type { ObjectKeyPaths, ValueAtPath } from './object-key-paths.interface';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 提取对象的 key 用 . 拼接成 path 形式
3
+ * type T1 = ObjectKeyPaths<{ name: string; age: number }>; // expected to be 'name' | 'age'
4
+ * type T2 = ObjectKeyPaths<{
5
+ * refCount: number;
6
+ * person: { name: string; age: number };
7
+ * }>; // expected to be 'refCount' | 'person' | 'person.name' | 'person.age'
8
+ */
9
+
10
+ type GenNode<K extends string | number, IsRoot extends boolean> = IsRoot extends true
11
+ ? `${K}`
12
+ : `.${K}` | (K extends number ? `[${K}]` : never);
13
+
14
+ export type ObjectKeyPaths<
15
+ T extends Record<string, unknown>,
16
+ IsRoot extends boolean = true,
17
+ K extends keyof T = keyof T,
18
+ > = K extends string | number
19
+ ?
20
+ | GenNode<K, IsRoot>
21
+ | (T[K] extends Record<string, unknown> ? `${GenNode<K, IsRoot>}${ObjectKeyPaths<T[K], false>}` : never)
22
+ : never;
23
+
24
+ /**
25
+ * 获取对象 path 对应的类型
26
+ * type T = ValueAtPath<{ a: { b: number } }, 'a.b'>; // expected to be number
27
+ */
28
+ export type ValueAtPath<
29
+ T extends Record<string, unknown>, // 泛型类型参数 T 表示对象类型
30
+ P extends ObjectKeyPaths<T>, // 泛型类型参数 P 表示路径字符串,必须是 T 可能存在的所有路径之一
31
+ > = P extends `${infer K}.${infer R}` // 如果 P 包含 "." 分隔符,则将其拆分成两部分 K 和 R
32
+ ? K extends keyof T // 如果 K 是 T 的属性之一
33
+ ? T[K] extends Record<string, unknown>
34
+ ? // @ts-ignore
35
+ ValueAtPath<T[K], R> // 递归地获取 T[K] 对应的子对象中的 R 路径属性的值
36
+ : never // 否则返回 never 类型(表示不存在)
37
+ : never
38
+ : P extends keyof T // 如果 P 不包含 "." 分隔符,并且是 T 的属性之一
39
+ ? T[P] // 直接返回 T 中对应属性的值
40
+ : never; // 否则返回 never 类型(表示不存在)
@@ -0,0 +1,61 @@
1
+ # UndoRedo栈
2
+ 提供了基础的undoredo栈规范,具体业务方可以直接使用或者继承使用。
3
+
4
+ ## StateUndoRedoStack
5
+ state形式undoredo栈的实现,类似Redux这种形式,使用方只需要消费当前的state。
6
+ ```
7
+ // 用法举例
8
+ const stack = new StateUndoRedoStack<T>(initialState);
9
+
10
+ stack.onDidRedo((state) => {
11
+ UI.reset(state);
12
+ });
13
+ stack.onDidUndo((state) => {
14
+ UI.reset(state);
15
+ });
16
+
17
+ ```
18
+
19
+ 特点:
20
+ - 每次只会有一个state变更,不会undo的时候,连续触发两个state行为。
21
+ - 不建议继承并重写方法,因为这种模式的undoRedoStack,本身就是简单场景使用。
22
+
23
+ ## ActionUndoRedoStack
24
+ action形式undoredo栈的实现,相比较state形式会复杂一些,业务方需要明确action存在undo和redo两种行为。
25
+
26
+ ### ActionStackElement
27
+ action形式栈中的元素,需要使用方满足接口。
28
+ 需要提供`undo`方法和`redo`方法即可。
29
+ 下面是一个简单的`IActionStackElement`实现举例:
30
+ ```
31
+ class CommandElement<T> implement IUndoRedoElement {
32
+ private _currentCommand: T;
33
+ private _invertCommand: T;
34
+
35
+ undo() {
36
+ this._invertCommand.execute();
37
+ this._reverse();
38
+ }
39
+
40
+ redo() {
41
+ this._invertCommand.execute();
42
+ this._reverse();
43
+ }
44
+
45
+ private _reverse() {
46
+ swap(this._currentCommand, this._invertCommand);
47
+ }
48
+ }
49
+ ```
50
+
51
+ 特点:
52
+ - 禁止继承时重写`undo`,`redo`,`pushElement`这三个方法,因为重写的话会影响生命周期行为。
53
+ - 提供默认的容量能力控制,可以重写`isOverflow`方法来业务精细化判断容量大小。
54
+ - **可以复写`popPastElements`和`popFutureElements`来实现定制化的出栈逻辑。**
55
+
56
+
57
+ ## 其他
58
+ - 如果需要其他生命周期,请联系基建侧同学。
59
+ - ActionUndoRedoStack中每一次undo、redo执行的粒度是数组,是因为业务场景中可能有联动出栈的情况。
60
+ - **如果本身是state场景,但是有一些复杂的逻辑,可以使用Action形式栈模拟。**
61
+ - Past、Future命名参考于vscode和redux。
@@ -0,0 +1,330 @@
1
+ import type { IActionStackElement } from './element';
2
+ import { BaseActionUndoRedoStack } from './action-stack';
3
+
4
+ class Data implements IActionStackElement {
5
+ constructor(
6
+ private readonly _undo: () => void,
7
+ private readonly _redo: () => void,
8
+ ) {}
9
+
10
+ undo() {
11
+ this._undo();
12
+ }
13
+
14
+ redo() {
15
+ this._redo();
16
+ }
17
+ }
18
+
19
+ describe('BaseActionUndoRedoStack', () => {
20
+ // 默认情况不能undo
21
+ it('canUndo1', () => {
22
+ const stack = new BaseActionUndoRedoStack();
23
+ expect(stack.canUndo()).toBeFalsy();
24
+ });
25
+
26
+ // 有了数据,可以undo
27
+ it('canUndo2', () => {
28
+ const stack = new BaseActionUndoRedoStack();
29
+ const elem = new Data(vi.fn(), vi.fn());
30
+ stack.pushElement(elem);
31
+ expect(stack.canUndo()).toBeTruthy();
32
+ });
33
+
34
+ // 有数据,但是被undo过了
35
+ it('canUndo3', () => {
36
+ const stack = new BaseActionUndoRedoStack();
37
+ const elem = new Data(vi.fn(), vi.fn());
38
+ stack.pushElement(elem);
39
+ stack.undo();
40
+ expect(stack.canUndo()).toBeFalsy();
41
+ });
42
+
43
+ // 默认情况不能redo
44
+ it('canRedo1', () => {
45
+ const stack = new BaseActionUndoRedoStack();
46
+ expect(stack.canRedo()).toBeFalsy();
47
+ });
48
+
49
+ // 添加了数据,还是不能redo
50
+ it('canRedo2', () => {
51
+ const stack = new BaseActionUndoRedoStack();
52
+ const elem = new Data(vi.fn(), vi.fn());
53
+ stack.pushElement(elem);
54
+ expect(stack.canRedo()).toBeFalsy();
55
+ });
56
+
57
+ // undo过了,可以redo
58
+ it('canRedo3', () => {
59
+ const stack = new BaseActionUndoRedoStack();
60
+ const elem = new Data(vi.fn(), vi.fn());
61
+ stack.pushElement(elem);
62
+ stack.undo();
63
+ expect(stack.canRedo()).toBeTruthy();
64
+ });
65
+
66
+ // 本来可以redo,但是添加了新数据
67
+ it('canRedo4', () => {
68
+ const stack = new BaseActionUndoRedoStack();
69
+ const elem = new Data(vi.fn(), vi.fn());
70
+ stack.pushElement(elem);
71
+ stack.undo();
72
+ expect(stack.canRedo()).toBeTruthy();
73
+ stack.pushElement(elem);
74
+ expect(stack.canRedo()).toBeFalsy();
75
+ });
76
+
77
+ it('pushElements', () => {
78
+ const stack = new BaseActionUndoRedoStack(2);
79
+ const fn = vi.fn();
80
+ stack.onStackChange(fn);
81
+ const elem1 = new Data(vi.fn(), vi.fn());
82
+ stack.pushElement(elem1);
83
+ expect(fn).toBeCalledTimes(1);
84
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
85
+ expect(stack['_past'].length).toBe(1);
86
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
87
+ expect(stack['_future'].length).toBe(0);
88
+
89
+ const elem2 = new Data(vi.fn(), vi.fn());
90
+ stack.pushElement(elem2);
91
+ expect(fn).toBeCalledTimes(2);
92
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
93
+ expect(stack['_past'].length).toBe(2);
94
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
95
+ expect(stack['_future'].length).toBe(0);
96
+
97
+ stack.undo();
98
+ expect(fn).toBeCalledTimes(3);
99
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
100
+ expect(stack['_past'].length).toBe(1);
101
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
102
+ expect(stack['_future'].length).toBe(1);
103
+
104
+ const elem3 = new Data(vi.fn(), vi.fn());
105
+ stack.pushElement(elem3);
106
+ expect(fn).toBeCalledTimes(4);
107
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
108
+ expect(stack['_past'].length).toBe(2);
109
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
110
+ expect(stack['_future'].length).toBe(0);
111
+
112
+ const elem4 = new Data(vi.fn(), vi.fn());
113
+ stack.pushElement(elem4);
114
+ expect(fn).toBeCalledTimes(5);
115
+ // 命中了最大限制,长度还是2个
116
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
117
+ expect(stack['_past'].length).toBe(2);
118
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
119
+ expect(stack['_past'][1]).toBe(elem4);
120
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
121
+ expect(stack['_past'][0]).toBe(elem3);
122
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
123
+ expect(stack['_future'].length).toBe(0);
124
+ });
125
+
126
+ // 没有数据时候undo
127
+ it('undo1', () => {
128
+ const stack = new BaseActionUndoRedoStack();
129
+ const fn = vi.fn();
130
+ stack.onDidUndo(fn);
131
+ stack.undo();
132
+ expect(fn).toBeCalledTimes(0);
133
+ });
134
+
135
+ // 有数据时候undo
136
+ it('undo2', () => {
137
+ const stack = new BaseActionUndoRedoStack();
138
+ const fn = vi.fn();
139
+ stack.onDidUndo(fn);
140
+ const undoFn = vi.fn();
141
+ const redoFn = vi.fn();
142
+ const elem = new Data(undoFn, redoFn);
143
+ stack.pushElement(elem);
144
+ stack.undo();
145
+ expect(fn).toBeCalledTimes(1);
146
+ expect(undoFn).toBeCalledTimes(1);
147
+ expect(redoFn).toBeCalledTimes(0);
148
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
149
+ expect(stack['_past'].length).toBe(0);
150
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
151
+ expect(stack['_future'].length).toBe(1);
152
+ });
153
+
154
+ // 没有数据时候redo
155
+ it('redo1', () => {
156
+ const stack = new BaseActionUndoRedoStack();
157
+ const fn = vi.fn();
158
+ stack.onDidUndo(fn);
159
+ stack.redo();
160
+ expect(fn).toBeCalledTimes(0);
161
+ });
162
+
163
+ // 有数据时候redo
164
+ it('redo2', () => {
165
+ const stack = new BaseActionUndoRedoStack();
166
+ const fn = vi.fn();
167
+ stack.onDidRedo(fn);
168
+ const undoFn = vi.fn();
169
+ const redoFn = vi.fn();
170
+ const elem = new Data(undoFn, redoFn);
171
+ stack.pushElement(elem);
172
+ stack.undo();
173
+ expect(fn).toBeCalledTimes(0);
174
+ expect(undoFn).toBeCalledTimes(1);
175
+ expect(redoFn).toBeCalledTimes(0);
176
+
177
+ stack.redo();
178
+ expect(fn).toBeCalledTimes(1);
179
+ expect(undoFn).toBeCalledTimes(1);
180
+ expect(redoFn).toBeCalledTimes(1);
181
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
182
+ expect(stack['_past'].length).toBe(1);
183
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
184
+ expect(stack['_future'].length).toBe(0);
185
+ });
186
+
187
+ it('clear', () => {
188
+ const fn = vi.fn();
189
+ const stack = new BaseActionUndoRedoStack();
190
+ stack.onStackChange(fn);
191
+
192
+ const undoFn = vi.fn();
193
+ const redoFn = vi.fn();
194
+ const elem = new Data(undoFn, redoFn);
195
+
196
+ // 本身没有元素,所以没有抛出事件
197
+ stack.clearRedo();
198
+ stack.clearUndo();
199
+ stack.reset();
200
+ expect(fn).toBeCalledTimes(0);
201
+
202
+ // 有undo元素,但是清除
203
+ stack.pushElement(elem);
204
+ fn.mockReset();
205
+ expect(stack.canUndo()).toBeTruthy();
206
+ stack.clearUndo();
207
+ expect(fn).toBeCalledTimes(1);
208
+ expect(stack.canUndo()).toBeFalsy();
209
+
210
+ // 有redo元素,但是清除
211
+ stack.pushElement(elem);
212
+ stack.pushElement(elem);
213
+ stack.pushElement(elem);
214
+ stack.undo();
215
+ fn.mockReset();
216
+ expect(stack.canRedo()).toBeTruthy();
217
+ stack.clearRedo();
218
+ expect(fn).toBeCalledTimes(1);
219
+ expect(stack.canRedo()).toBeFalsy();
220
+
221
+ stack.undo();
222
+ expect(stack.canUndo()).toBeTruthy();
223
+ expect(stack.canRedo()).toBeTruthy();
224
+ fn.mockReset();
225
+ stack.reset();
226
+ expect(fn).toBeCalledTimes(1);
227
+ expect(stack.canUndo()).toBeFalsy();
228
+ expect(stack.canRedo()).toBeFalsy();
229
+ });
230
+ });
231
+
232
+ describe('DerivedUndoRedoStack', () => {
233
+ // 整一个奇怪的undoredostack,主要是测试复写基类方法
234
+ class UntrustedUndoRedoStack extends BaseActionUndoRedoStack<IActionStackElement> {
235
+ canUndo() {
236
+ return true;
237
+ }
238
+
239
+ canRedo() {
240
+ return true;
241
+ }
242
+
243
+ protected _popPastElements(): IActionStackElement[] {
244
+ const elems = [...this._past];
245
+ this._past.length = 0;
246
+ return elems;
247
+ }
248
+
249
+ protected _popFutureElements(): IActionStackElement[] {
250
+ const elems = [...this._future];
251
+ this._future.length = 0;
252
+ return elems;
253
+ }
254
+
255
+ protected _isOverflow(_elem: IActionStackElement) {
256
+ if (this._future.length > 0) {
257
+ return true;
258
+ }
259
+ return false;
260
+ }
261
+ }
262
+
263
+ // 虽然canUndo永远是true,但是undo没有真的触发,所以不会抛出事件
264
+ it('undo1', () => {
265
+ const stack = new UntrustedUndoRedoStack();
266
+ const fn = vi.fn();
267
+ stack.onDidUndo(fn);
268
+ stack.undo();
269
+ expect(fn).toBeCalledTimes(0);
270
+ });
271
+
272
+ // 验证_popPastElements重写成功
273
+ it('undo2', () => {
274
+ const stack = new UntrustedUndoRedoStack();
275
+ const fn = vi.fn();
276
+ stack.onDidUndo(fn);
277
+ const undoFn = vi.fn();
278
+ const redoFn = vi.fn();
279
+ const elem = new Data(undoFn, redoFn);
280
+ // 添加了三次
281
+ stack.pushElement(elem);
282
+ stack.pushElement(elem);
283
+ stack.pushElement(elem);
284
+ stack.undo();
285
+ expect(fn).toBeCalledTimes(1);
286
+ expect(undoFn).toBeCalledTimes(3);
287
+ expect(redoFn).toBeCalledTimes(0);
288
+ });
289
+
290
+ // 虽然canRedo永远是true,但是redo没有真的触发,所以不会抛出事件
291
+ it('redo1', () => {
292
+ const stack = new UntrustedUndoRedoStack();
293
+ const fn = vi.fn();
294
+ stack.onDidRedo(fn);
295
+ stack.redo();
296
+ expect(fn).toBeCalledTimes(0);
297
+ });
298
+
299
+ // 验证_popFutureElements重写成功
300
+ it('redo2', () => {
301
+ const stack = new UntrustedUndoRedoStack();
302
+ const fn = vi.fn();
303
+ stack.onDidRedo(fn);
304
+ const undoFn = vi.fn();
305
+ const redoFn = vi.fn();
306
+ const elem = new Data(undoFn, redoFn);
307
+ // 添加了三次
308
+ stack.pushElement(elem);
309
+ stack.pushElement(elem);
310
+ stack.pushElement(elem);
311
+ stack.undo();
312
+ stack.redo();
313
+ expect(fn).toBeCalledTimes(1);
314
+ expect(undoFn).toBeCalledTimes(3);
315
+ expect(redoFn).toBeCalledTimes(3);
316
+ });
317
+
318
+ // 验证_isOverflow重写成功
319
+ it('isOverflow', () => {
320
+ const stack = new UntrustedUndoRedoStack(1);
321
+ const elem = new Data(vi.fn(), vi.fn());
322
+ stack.pushElement(elem);
323
+ stack.pushElement(elem);
324
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
325
+ expect(stack['_isOverflow'](elem)).toBeFalsy();
326
+ stack.undo();
327
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
328
+ expect(stack['_isOverflow'](elem)).toBeTruthy();
329
+ });
330
+ });