@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,85 @@
1
+ import { ignoreDispose } from '@/dispose';
2
+ import { LRUCache } from './lru';
3
+
4
+ export class LRUCacheWithTimeout<T, K = string> {
5
+ private readonly _updateTime: Map<K, number> = new Map();
6
+ private _timer?: NodeJS.Timeout;
7
+ private readonly _lru: LRUCache<T, K>;
8
+
9
+ constructor(
10
+ capacity: number,
11
+ private readonly _timeout: number,
12
+ ) {
13
+ this._lru = new LRUCache(capacity);
14
+
15
+ ignoreDispose(
16
+ this._lru.onEvicted((key: K) => {
17
+ this._updateTime.delete(key);
18
+ }),
19
+ );
20
+ }
21
+
22
+ get(key: K): T | undefined {
23
+ const result = this._lru.get(key);
24
+ if (result) {
25
+ this._updateTime.set(key, Date.now() + this._timeout);
26
+ }
27
+ return result;
28
+ }
29
+
30
+ put(key: K, value: T): void {
31
+ this._startTimer();
32
+ this._updateTime.set(key, Date.now() + this._timeout);
33
+ return this._lru.put(key, value);
34
+ }
35
+
36
+ remove(key: K): void {
37
+ this._updateTime.delete(key);
38
+ return this._lru.remove(key);
39
+ }
40
+
41
+ size(): number {
42
+ return this._lru.size();
43
+ }
44
+
45
+ clear(): void {
46
+ this._updateTime.clear();
47
+ return this._lru.clear();
48
+ }
49
+
50
+ dispose(): void {
51
+ this.clear();
52
+ clearTimeout(this._timer);
53
+ }
54
+
55
+ private _startTimer() {
56
+ if (this._timer) {
57
+ return;
58
+ }
59
+ this._timer = setTimeout(this._tick, this._timeout);
60
+ }
61
+
62
+ private _check() {
63
+ const now = Date.now();
64
+ const shouldRemove: K[] = [];
65
+ for (const [key, time] of this._updateTime) {
66
+ if (time <= now) {
67
+ shouldRemove.push(key);
68
+ }
69
+ }
70
+ for (const key of shouldRemove) {
71
+ this._updateTime.delete(key);
72
+ this._lru.remove(key);
73
+ }
74
+ }
75
+
76
+ private readonly _tick = () => {
77
+ this._check();
78
+ if (this._lru.size() === 0) {
79
+ // 不再轮询
80
+ this._timer = undefined;
81
+ return;
82
+ }
83
+ this._timer = setTimeout(this._tick, this._timeout);
84
+ };
85
+ }
@@ -0,0 +1,56 @@
1
+ import { LRUCache } from './lru';
2
+
3
+ class Foo {
4
+ constructor(public readonly value: string) {}
5
+ }
6
+
7
+ describe('LRUCache', () => {
8
+ let cache: LRUCache<Foo>;
9
+
10
+ beforeEach(() => {
11
+ // 创建一个容量为5的缓存实例
12
+ cache = new LRUCache<Foo>(5);
13
+
14
+ // 向缓存中添加一些初始数据供测试使用
15
+ cache.put('1', new Foo('apple'));
16
+ cache.put('2', new Foo('banana'));
17
+ cache.put('3', new Foo('orange'));
18
+ });
19
+
20
+ it('should return the value when getting an existing key', () => {
21
+ const result = cache.get('2');
22
+ expect(result).not.toBeUndefined();
23
+ expect(result!.value).toBe('banana');
24
+ });
25
+
26
+ it('should return undefined when getting a non-existing key', () => {
27
+ const result = cache.get('4');
28
+ expect(result).toBeUndefined();
29
+ });
30
+
31
+ it('should update the value when putting an existing key', () => {
32
+ cache.put('2', new Foo('grapefruit'));
33
+ const result = cache.get('2');
34
+ expect(result).not.toBeUndefined();
35
+ expect(result!.value).toBe('grapefruit');
36
+ });
37
+
38
+ it('should add the key-value pair to the cache when putting a new key', () => {
39
+ cache.put('4', new Foo('kiwi'));
40
+ const result = cache.get('4');
41
+ expect(result).not.toBeUndefined();
42
+ expect(result!.value).toBe('kiwi');
43
+ });
44
+
45
+ it('should remove the least recently used item when the cache is full and a new item is added', () => {
46
+ cache.put('4', new Foo('kiwi'));
47
+ cache.put('5', new Foo('pear'));
48
+ cache.put('6', new Foo('mango'));
49
+ // 检查最早添加的项是否被移除
50
+ const result1 = cache.get('1');
51
+ const result2 = cache.get('2');
52
+ expect(result1).toBeUndefined();
53
+ expect(result2).not.toBeUndefined();
54
+ expect(result2!.value).toBe('banana');
55
+ });
56
+ });
@@ -0,0 +1,59 @@
1
+ import { Emitter, type Event } from '@/event';
2
+
3
+ /**
4
+ * LRUCache
5
+ * T 是值类型
6
+ * K 是索引类型,默认string
7
+ */
8
+ export class LRUCache<T, K = string> {
9
+ protected readonly _cache: Map<K, T> = new Map();
10
+ private _onEvicted?: Emitter<[K, T]>;
11
+
12
+ constructor(private readonly _capacity: number) {}
13
+
14
+ get onEvicted(): Event<[K, T]> {
15
+ if (!this._onEvicted) {
16
+ this._onEvicted = new Emitter();
17
+ }
18
+ return this._onEvicted.event;
19
+ }
20
+
21
+ get(key: K): T | undefined {
22
+ const value = this._cache.get(key);
23
+ if (value) {
24
+ // 将访问过的 key 移到最近使用的位置
25
+ this._cache.delete(key);
26
+ this._cache.set(key, value);
27
+ }
28
+ return value;
29
+ }
30
+
31
+ put(key: K, value: T): void {
32
+ if (this._cache.has(key)) {
33
+ // 如果已存在该 key,则将其移动到最近使用的位置
34
+ this._cache.delete(key);
35
+ } else if (this._cache.size >= this._capacity) {
36
+ // 如果已达到容量上限,则删除最久未使用的键值对
37
+ const oldestKey = this._cache.keys().next().value as K;
38
+ const oldestVal = this._onEvicted ? this._cache.get(oldestKey)! : null;
39
+ this._cache.delete(oldestKey);
40
+ this._onEvicted?.fire(oldestKey, oldestVal!);
41
+ }
42
+ this._cache.set(key, value);
43
+ }
44
+
45
+ remove(key: K): void {
46
+ const obj = this._cache.get(key);
47
+ if (obj) {
48
+ this._cache.delete(key);
49
+ }
50
+ }
51
+
52
+ size(): number {
53
+ return this._cache.size;
54
+ }
55
+
56
+ clear(): void {
57
+ this._cache.clear();
58
+ }
59
+ }
@@ -0,0 +1,17 @@
1
+ import { makeEntryContext, makeUserInputContext } from './context';
2
+
3
+ describe('context', () => {
4
+ it('bind', () => {
5
+ const context = makeEntryContext();
6
+ expect(context.getValue('lvweb')).toBeUndefined();
7
+ context.setValue('lvweb', true);
8
+ expect(context.getValue('lvweb')).toBeTruthy();
9
+ });
10
+
11
+ it('background', () => {
12
+ const context = makeUserInputContext();
13
+ context.setValue('lvweb', true);
14
+ const newContext = context.background();
15
+ expect(newContext.getValue('lvweb')).toBeUndefined();
16
+ });
17
+ });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Context类型
3
+ */
4
+ export enum ContextType {
5
+ // 入口
6
+ Entry,
7
+ // 事件
8
+ Event,
9
+ // 用户
10
+ UserInput,
11
+ // 自定义任务
12
+ Task,
13
+ }
14
+
15
+ export class Context {
16
+ private readonly _store = new Map<string, any>();
17
+
18
+ constructor(public readonly type: ContextType = ContextType.Task) {}
19
+
20
+ /**
21
+ * 获取一个纯粹的上下文
22
+ */
23
+ background() {
24
+ return new Context(this.type);
25
+ }
26
+
27
+ /**
28
+ * 绑定信息
29
+ */
30
+ setValue<T>(key: string, value: T) {
31
+ this._store.set(key, value);
32
+ }
33
+
34
+ /**
35
+ * 获取信息
36
+ */
37
+ getValue<T>(key: string) {
38
+ return this._store.get(key) as T | undefined;
39
+ }
40
+ }
41
+
42
+ export function makeEntryContext() {
43
+ return new Context(ContextType.Entry);
44
+ }
45
+
46
+ export function makeEventContext() {
47
+ return new Context(ContextType.Event);
48
+ }
49
+
50
+ export function makeUserInputContext() {
51
+ return new Context(ContextType.UserInput);
52
+ }
53
+
54
+ export function makeTaskContext() {
55
+ return new Context(ContextType.Task);
56
+ }
57
+
58
+ export function makeContext() {
59
+ return new Context();
60
+ }
@@ -0,0 +1,8 @@
1
+ export { Context, ContextType } from './context';
2
+ export {
3
+ makeEntryContext,
4
+ makeEventContext,
5
+ makeUserInputContext,
6
+ makeTaskContext,
7
+ makeContext,
8
+ } from './context';
package/src/di/base.ts ADDED
@@ -0,0 +1,73 @@
1
+ // service特征标识
2
+ export type BrandedService = { _serviceBrand: undefined };
3
+
4
+ //
5
+ // 服务唯一标识符(编译时生成)
6
+ // 需要DI进行注入的服务必须拥有该标识符
7
+ // 本质上是一个参数装饰器
8
+ //
9
+ export interface ServiceIdentifier<T> {
10
+ (...args: any[]): void;
11
+ type: T;
12
+ }
13
+
14
+ // 获取服务的视图接口
15
+ export interface ServicesAccessor {
16
+ get: <T>(id: ServiceIdentifier<T>) => T;
17
+ }
18
+
19
+ // 服务唯一标识符存储
20
+ const serviceIds = new Map<string, ServiceIdentifier<any>>();
21
+
22
+ export const DI_TARGET = '$di$target';
23
+ export const DI_DEPENDENCIES = '$di$dependencies';
24
+
25
+ // 获取某个服务的依赖
26
+ // 因为服务依赖关系会存放在构造函数的属性上
27
+ export function getServiceDependencies(ctor: any): { id: ServiceIdentifier<any>; index: number }[] {
28
+ return ctor[DI_DEPENDENCIES] || [];
29
+ }
30
+
31
+ // 更新服务依赖依赖关系
32
+ function setServiceDependency(id: ServiceIdentifier<any>, ctor: any, index: number): void {
33
+ if (ctor[DI_TARGET] === ctor) {
34
+ ctor[DI_DEPENDENCIES].push({ id, index });
35
+ } else {
36
+ ctor[DI_DEPENDENCIES] = [{ id, index }];
37
+ ctor[DI_TARGET] = ctor;
38
+ }
39
+ }
40
+
41
+ //
42
+ // 创建服务唯一标识符
43
+ // 传入服务ID,返回一个参数装饰器
44
+ // 参数装饰器会记录A需要
45
+ // const IFooServiceId = createDecorator<FooService>('FooService');
46
+ //
47
+ // class Bar
48
+ // constructor(@IFooServiceId a: IFooService) // IFooService是接口声明
49
+ //
50
+ export function createDecorator<T>(serviceId: string): ServiceIdentifier<T> {
51
+ if (serviceIds.has(serviceId)) {
52
+ return serviceIds.get(serviceId)!;
53
+ }
54
+
55
+ const id = function (target: any, key: string, index: number): any {
56
+ if (arguments.length !== 3) {
57
+ throw new Error('@IServiceName-decorator can only be used to decorate a parameter');
58
+ }
59
+ setServiceDependency(id, target, index);
60
+ } as any;
61
+
62
+ id.toString = () => serviceId;
63
+
64
+ serviceIds.set(serviceId, id);
65
+ return id;
66
+ }
67
+
68
+ // TODO(niurouwan): 补一下注释和例子
69
+ export function refineServiceDecorator<T1, T extends T1>(
70
+ serviceIdentifier: ServiceIdentifier<T1>,
71
+ ): ServiceIdentifier<T> {
72
+ return serviceIdentifier as ServiceIdentifier<T>;
73
+ }
@@ -0,0 +1,179 @@
1
+ import { createDecorator } from './base';
2
+ import { InstantiationService as ContainerService, InstantiationService } from './instantiation-service';
3
+ import { ServiceOwnership } from './service-ownership-collection';
4
+ import { ServiceRegistry } from './service-registry';
5
+
6
+ /**
7
+ * 存在dispose的service1
8
+ */
9
+ class MockService1 {
10
+ readonly _serviceBrand: undefined;
11
+
12
+ constructor(private readonly _fn: () => void) {}
13
+
14
+ dispose() {
15
+ this._fn();
16
+ }
17
+ }
18
+ const IMockService1 = createDecorator<MockService1>('MockService1');
19
+
20
+ /**
21
+ * 存在dispose的service2
22
+ */
23
+ class MockService2 {
24
+ readonly _serviceBrand: undefined;
25
+
26
+ constructor(private readonly _fn: () => void) {}
27
+
28
+ dispose() {
29
+ this._fn();
30
+ }
31
+ }
32
+ const IMockService2 = createDecorator<MockService2>('MockService2');
33
+
34
+ /**
35
+ * 不存在dispose的service
36
+ */
37
+ class MockService3 {
38
+ readonly _serviceBrand: undefined;
39
+
40
+ constructor(private readonly _fn: () => void) {}
41
+ }
42
+ const IMockService3 = createDecorator<MockService3>('MockService3');
43
+
44
+ /**
45
+ * reference service
46
+ */
47
+ class MockService4 {
48
+ readonly _serviceBrand: undefined;
49
+
50
+ constructor(private readonly _fn: () => void) {}
51
+
52
+ dispose() {
53
+ this._fn();
54
+ }
55
+ }
56
+ const IMockService4 = createDecorator<MockService4>('MockService4');
57
+
58
+ describe('ContainerService', () => {
59
+ // 单层的dispose
60
+ it('dispose1', () => {
61
+ const fn1 = vi.fn();
62
+ const fn2 = vi.fn();
63
+ const fn3 = vi.fn();
64
+
65
+ const registry = new ServiceRegistry();
66
+ registry.registerInstance(IMockService1, new MockService1(fn1));
67
+ registry.registerInstance(IMockService2, new MockService2(fn2));
68
+ registry.registerInstance(IMockService3, new MockService3(fn3));
69
+ const containerService = new ContainerService(registry.makeCollection());
70
+ containerService.dispose();
71
+
72
+ expect(fn1).toBeCalled();
73
+ expect(fn2).toBeCalled();
74
+ expect(fn3).not.toBeCalled();
75
+ });
76
+
77
+ // 双层的dispose,一起销毁
78
+ it('dispose2', () => {
79
+ const fn1 = vi.fn();
80
+ const fn2 = vi.fn();
81
+ const fn3 = vi.fn();
82
+
83
+ const registry1 = new ServiceRegistry();
84
+ registry1.registerInstance(IMockService1, new MockService1(fn1));
85
+ const containerService = new ContainerService(registry1.makeCollection());
86
+
87
+ const registry2 = new ServiceRegistry();
88
+ registry2.registerInstance(IMockService2, new MockService2(fn2));
89
+ registry2.registerInstance(IMockService3, new MockService3(fn3));
90
+ const childContainerService = new ContainerService(registry2.makeCollection(), containerService);
91
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
92
+ expect(containerService['_childs'].has(childContainerService)).toBeTruthy();
93
+
94
+ containerService.dispose();
95
+
96
+ expect(fn1).toBeCalled();
97
+ expect(fn2).toBeCalled();
98
+ expect(fn3).not.toBeCalled();
99
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
100
+ expect(containerService['_childs'].has(childContainerService)).toBeFalsy();
101
+ });
102
+
103
+ // 双层的dispose,只销毁下一层
104
+ it('dispose3', () => {
105
+ const fn1 = vi.fn();
106
+ const fn2 = vi.fn();
107
+ const fn3 = vi.fn();
108
+
109
+ const registry1 = new ServiceRegistry();
110
+ registry1.registerInstance(IMockService1, new MockService1(fn1));
111
+ const containerService = new ContainerService(registry1.makeCollection());
112
+
113
+ const registry2 = new ServiceRegistry();
114
+ registry2.registerInstance(IMockService2, new MockService2(fn2));
115
+ registry2.registerInstance(IMockService3, new MockService3(fn3));
116
+ const childContainerService = new ContainerService(registry2.makeCollection(), containerService);
117
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
118
+ expect(containerService['_childs'].has(childContainerService)).toBeTruthy();
119
+
120
+ childContainerService.dispose();
121
+
122
+ expect(fn1).not.toBeCalled();
123
+ expect(fn2).toBeCalled();
124
+ expect(fn3).not.toBeCalled();
125
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
126
+ expect(containerService['_childs'].has(childContainerService)).toBeFalsy();
127
+ });
128
+
129
+ // parent是instantiationService,正常dispose
130
+ it('dispose4', () => {
131
+ const fn1 = vi.fn();
132
+ const fn2 = vi.fn();
133
+ const fn3 = vi.fn();
134
+
135
+ const registry1 = new ServiceRegistry();
136
+ registry1.registerInstance(IMockService1, new MockService1(fn1));
137
+ const instantiationService = new InstantiationService(registry1.makeCollection());
138
+
139
+ const registry2 = new ServiceRegistry();
140
+ registry2.registerInstance(IMockService2, new MockService2(fn2));
141
+ registry2.registerInstance(IMockService3, new MockService3(fn3));
142
+ const containerService = new ContainerService(registry2.makeCollection(), instantiationService);
143
+
144
+ containerService.dispose();
145
+
146
+ expect(fn1).not.toBeCalled();
147
+ expect(fn2).toBeCalled();
148
+ expect(fn3).not.toBeCalled();
149
+ });
150
+
151
+ // reference dispose
152
+ it('reference dispose', () => {
153
+ const fn1 = vi.fn();
154
+ const fn2 = vi.fn();
155
+ const fn4 = vi.fn();
156
+
157
+ const mock4Instance = new MockService4(fn4);
158
+ const registry1 = new ServiceRegistry();
159
+ registry1.registerInstance(IMockService1, new MockService1(fn1));
160
+ registry1.registerInstance(IMockService4, mock4Instance);
161
+ const containerService = new ContainerService(registry1.makeCollection());
162
+
163
+ const registry2 = new ServiceRegistry();
164
+ registry2.registerInstance(IMockService2, new MockService2(fn2));
165
+ registry2.registerInstance(IMockService4, mock4Instance, {
166
+ ownership: ServiceOwnership.Reference,
167
+ });
168
+ const childContainerService = new ContainerService(registry2.makeCollection(), containerService);
169
+ childContainerService.dispose();
170
+
171
+ expect(fn1).not.toBeCalled();
172
+ expect(fn2).toBeCalled();
173
+ expect(fn4).not.toBeCalled();
174
+
175
+ containerService.dispose();
176
+ expect(fn1).toBeCalled();
177
+ expect(fn4).toBeCalled();
178
+ });
179
+ });
@@ -0,0 +1,41 @@
1
+ import { createContext, createElement, useContext, useMemo, type ReactElement } from 'react';
2
+ import { lvAssertNotNil } from '@/assert';
3
+ import type { IInstantiationService } from './instantiation-service.interface';
4
+ import type { ServiceIdentifier, ServicesAccessor } from './base';
5
+
6
+ interface IProps {
7
+ instantiationService: IInstantiationService;
8
+ children?: React.ReactNode;
9
+ }
10
+
11
+ const Context = createContext<IInstantiationService | null>(null);
12
+
13
+ /**
14
+ * 组件支持依赖注入上下文
15
+ */
16
+ export const InstantiationContext = (props: IProps) => {
17
+ return createElement(
18
+ Context.Provider,
19
+ { value: props.instantiationService },
20
+ props.children,
21
+ ) as ReactElement<any, any>;
22
+ };
23
+
24
+ /**
25
+ * 获取服务的hook
26
+ * @param identifier 服务标识符
27
+ * @returns 对应服务
28
+ */
29
+ export function useService<T>(identifier: ServiceIdentifier<T>): T {
30
+ const instantiationService = useContext(Context);
31
+ lvAssertNotNil(instantiationService, 'react components need service context.');
32
+ const service = useMemo(
33
+ () =>
34
+ instantiationService.invokeFunction((servicesAccessor: ServicesAccessor) =>
35
+ servicesAccessor.get(identifier),
36
+ ),
37
+ [instantiationService, identifier],
38
+ );
39
+
40
+ return service;
41
+ }
@@ -0,0 +1,31 @@
1
+ //
2
+ // DI中服务描述符,本质上是构造函数的包装
3
+ //
4
+ // 必须提供服务构造函数
5
+ // 支持静态参数
6
+ // 支持配置是否延迟初始化
7
+ //
8
+ export class SyncDescriptor<T> {
9
+ readonly ctor: new (...args: any[]) => T;
10
+ readonly staticArguments: any[];
11
+ readonly supportsDelayedInstantiation: boolean;
12
+
13
+ constructor(
14
+ ctor: new (...args: any[]) => T,
15
+ staticArguments: any[] = [],
16
+ supportsDelayedInstantiation = false,
17
+ ) {
18
+ this.ctor = ctor;
19
+ this.staticArguments = staticArguments;
20
+ this.supportsDelayedInstantiation = supportsDelayedInstantiation;
21
+ }
22
+ }
23
+
24
+ //
25
+ // 特化描述符
26
+ // 1. 没有静态参数,没有动态参数,只存在注入参数
27
+ // 2. 默认延迟初始化
28
+ //
29
+ export interface SyncDescriptor0<T> {
30
+ readonly ctor: new () => T;
31
+ }
@@ -0,0 +1,73 @@
1
+ import { sleep } from '@/async';
2
+ import { IdleValue } from './idle-value';
3
+
4
+ class Foo {
5
+ value = 'public value.';
6
+
7
+ private _data = 100;
8
+ private readonly _mockFn: () => void;
9
+
10
+ constructor(mockFn: () => void) {
11
+ this._mockFn = mockFn;
12
+ }
13
+
14
+ get data() {
15
+ return this._data;
16
+ }
17
+
18
+ set data(value: number) {
19
+ this._data = value;
20
+ }
21
+
22
+ test() {
23
+ this._mockFn();
24
+ }
25
+ }
26
+
27
+ describe('idle value', () => {
28
+ it('initializes during idle time', async () => {
29
+ const fn = vi.fn();
30
+ const wrapper = new IdleValue<Foo>(() => new Foo(fn));
31
+ // Not initialized immediately
32
+ expect(wrapper.isInitialized).toBe(false);
33
+
34
+ expect(fn).not.toBeCalled();
35
+ expect(wrapper.isInitialized).toBe(false);
36
+
37
+ await sleep(500);
38
+
39
+ // Must have been initialized asynchronously
40
+ expect(wrapper.isInitialized).toBe(true);
41
+
42
+ // Properties work normally
43
+ expect(wrapper.value.value).toBe('public value.');
44
+ // Setters/getters work normally
45
+ expect(wrapper.value.data).toBe(100);
46
+ wrapper.value.data = 200;
47
+ expect(wrapper.value.data).toBe(200);
48
+ // Method calls work normally
49
+ wrapper.value.test();
50
+ expect(fn).toBeCalled();
51
+ });
52
+
53
+ it('initializes immediately due to usage', () => {
54
+ const fn = vi.fn();
55
+ const wrapper = new IdleValue<Foo>(() => new Foo(fn));
56
+ // Not initialized immediately
57
+ expect(wrapper.isInitialized).toBe(false);
58
+
59
+ // Properties work normally
60
+ expect(wrapper.value.value).toBe('public value.');
61
+ // Setters/getters work normally
62
+ expect(wrapper.value.data).toBe(100);
63
+ wrapper.value.data = 200;
64
+ expect(wrapper.value.data).toBe(200);
65
+ // Method calls work normally
66
+ wrapper.value.test();
67
+ expect(fn).toBeCalled();
68
+
69
+ // Initialized because value was accessed
70
+ expect(wrapper.isInitialized).toBe(true);
71
+ // await sleep(500);
72
+ });
73
+ });