@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,35 @@
1
+ import { trimStart, trimEnd } from './array';
2
+
3
+ describe('trimStart', () => {
4
+ it('trimStart', () => {
5
+ expect(trimStart([], () => true)).toEqual([]);
6
+
7
+ expect(trimStart([1, 2], () => true)).toEqual([]);
8
+
9
+ expect(trimStart([1, 2], (x) => x === 1)).toEqual([2]);
10
+
11
+ expect(trimStart([1, 2], (x) => x === 2)).toEqual([1, 2]);
12
+
13
+ expect(trimStart([1, 2], (x) => x === 3)).toEqual([1, 2]);
14
+
15
+ expect(trimStart([1, 1, 2], (x) => x === 1)).toEqual([2]);
16
+
17
+ expect(trimStart([1, 1, 1], (x) => x === 1)).toEqual([]);
18
+ });
19
+
20
+ it('trimEnd', () => {
21
+ expect(trimEnd([], () => true)).toEqual([]);
22
+
23
+ expect(trimEnd([2, 1], () => true)).toEqual([]);
24
+
25
+ expect(trimEnd([2, 1], (x) => x === 1)).toEqual([2]);
26
+
27
+ expect(trimEnd([2, 1], (x) => x === 2)).toEqual([2, 1]);
28
+
29
+ expect(trimEnd([2, 1], (x) => x === 3)).toEqual([2, 1]);
30
+
31
+ expect(trimEnd([2, 1, 1], (x) => x === 1)).toEqual([2]);
32
+
33
+ expect(trimEnd([1, 1, 1], (x) => x === 1)).toEqual([]);
34
+ });
35
+ });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 提供一系列数组的辅助函数
3
+ */
4
+
5
+ /**
6
+ * 去掉数组前面满足条件的项
7
+ */
8
+ export function trimStart<T>(arr: T[], condition: (element: T) => boolean): T[] {
9
+ let index = 0;
10
+ while (index < arr.length && condition(arr[index])) {
11
+ index++;
12
+ }
13
+ return arr.slice(index);
14
+ }
15
+
16
+ /**
17
+ * 去掉数组后面满足条件的项
18
+ */
19
+ export function trimEnd<T>(arr: T[], condition: (element: T) => boolean): T[] {
20
+ let index = arr.length - 1;
21
+ while (index >= 0 && condition(arr[index])) {
22
+ index--;
23
+ }
24
+ return arr.slice(0, index + 1);
25
+ }
@@ -0,0 +1 @@
1
+ export { trimStart, trimEnd } from './array';
@@ -0,0 +1,86 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ import { lvAssert, lvAssertNever, lvAssertNotHere, lvAssertNotNil } from './assert';
4
+
5
+ describe('assert', () => {
6
+ it('lvAssert', () => {
7
+ expect(() => {
8
+ lvAssert(false);
9
+ }).toThrow('lvAssert(#expr is false)');
10
+
11
+ expect(() => {
12
+ lvAssert(true);
13
+ }).not.toThrowError();
14
+
15
+ expect(() => {
16
+ const bool = true as boolean;
17
+ lvAssert(bool);
18
+ // assert 可以自动去掉 false
19
+ const _true: true = bool;
20
+ const str = 'hello' as string | undefined;
21
+ lvAssert(str);
22
+ // assert 可以自动去掉 undefined
23
+ const _str: string = str;
24
+ }).not.toThrowError();
25
+ });
26
+
27
+ it('lvAssertNotHere', () => {
28
+ expect(() => {
29
+ lvAssertNotHere();
30
+ // @ts-expect-error 前面已经断言抛异常了,后面代码必定不会被执行,应该报错
31
+ const _a = 1;
32
+ }).toThrow('lvAssert(unreachable code flow)');
33
+ });
34
+
35
+ it('lvAssertNotNil', () => {
36
+ expect(() => {
37
+ lvAssertNotNil(undefined);
38
+ }).toThrow('lvAssert(#val is nil)');
39
+
40
+ expect(() => {
41
+ lvAssertNotNil(null);
42
+ }).toThrow('lvAssert(#val is nil)');
43
+
44
+ expect(() => {
45
+ lvAssertNotNil({});
46
+ }).not.toThrowError();
47
+
48
+ expect(() => {
49
+ const nullableString = '' as string | undefined;
50
+ lvAssertNotNil(nullableString);
51
+ const _str: string = nullableString;
52
+ }).not.toThrowError();
53
+ });
54
+
55
+ it('lvAssertNever', () => {
56
+ enum ErrorCode {
57
+ A,
58
+ B,
59
+ C,
60
+ }
61
+
62
+ const errorCode = ErrorCode.A as ErrorCode;
63
+ const _handler1: () => 1 = () => {
64
+ switch (errorCode) {
65
+ case ErrorCode.A:
66
+ case ErrorCode.B:
67
+ return 1;
68
+ default:
69
+ // @ts-expect-error switch case 没有覆盖所有的 case,应该报错
70
+ lvAssertNever(errorCode);
71
+ }
72
+ };
73
+
74
+ const _handler2: () => 1 = () => {
75
+ switch (errorCode) {
76
+ case ErrorCode.A:
77
+ case ErrorCode.B:
78
+ case ErrorCode.C:
79
+ return 1;
80
+ default:
81
+ // 已覆盖全部 case
82
+ lvAssertNever(errorCode);
83
+ }
84
+ };
85
+ });
86
+ });
@@ -0,0 +1,42 @@
1
+ function abort(reason: string): never {
2
+ throw new Error(`lvAssert(${reason})`);
3
+ }
4
+
5
+ /**
6
+ * 断言表达式为真
7
+ * @param expr
8
+ * @param reason
9
+ */
10
+ export function lvAssert(expr: unknown, reason?: string): asserts expr {
11
+ if (!expr) {
12
+ abort(reason ?? '#expr is false');
13
+ }
14
+ }
15
+
16
+ /**
17
+ * 断言deadcode路径
18
+ * @param reason
19
+ */
20
+ export function lvAssertNotHere(reason?: string): never {
21
+ abort(reason ?? 'unreachable code flow');
22
+ }
23
+
24
+ /**
25
+ * 断言类型不可达
26
+ * @param member
27
+ * @param message
28
+ */
29
+ export function lvAssertNever(member: never, message = 'Illegal value:'): never {
30
+ abort(`${message}: ${member}`);
31
+ }
32
+
33
+ /**
34
+ * 断言变量为null或者undefined
35
+ * @param val
36
+ * @param reason
37
+ */
38
+ export function lvAssertNotNil<T>(val: T, reason?: string): asserts val is NonNullable<T> {
39
+ if (val === null || val === undefined) {
40
+ abort(reason ?? '#val is nil');
41
+ }
42
+ }
@@ -0,0 +1,2 @@
1
+ // 提供断言能力
2
+ export { lvAssert, lvAssertNotHere, lvAssertNever, lvAssertNotNil } from './assert';
@@ -0,0 +1,90 @@
1
+ import { Barrier, makeBarrierByPromise } from './barrier';
2
+
3
+ describe('barrier', () => {
4
+ it('barriers promise', async () => {
5
+ vi.useFakeTimers();
6
+ const before = Date.now();
7
+ const barrier = new Barrier();
8
+ expect(barrier.isOpen()).toBe(false);
9
+ setTimeout(() => {
10
+ barrier.open();
11
+ }, 300);
12
+ vi.advanceTimersByTime(300);
13
+ await barrier.wait();
14
+ expect(barrier.isOpen()).toBe(true);
15
+ expect(Date.now() - before).toBe(300);
16
+ });
17
+
18
+ // resolve成功
19
+ it('makeBarrierByPromise1', async () => {
20
+ vi.useFakeTimers();
21
+ const barrier = makeBarrierByPromise(
22
+ new Promise<void>((resolve) => {
23
+ setTimeout(() => {
24
+ resolve();
25
+ }, 300);
26
+ }),
27
+ );
28
+ vi.advanceTimersByTime(400);
29
+ // 涉及到promise,等待一次tick
30
+ await Promise.resolve();
31
+ expect(barrier.isOpen()).toBe(true);
32
+ });
33
+
34
+ // 一直在pending中
35
+ it('makeBarrierByPromise2', async () => {
36
+ vi.useFakeTimers();
37
+ const barrier = makeBarrierByPromise(
38
+ new Promise<void>((resolve) => {
39
+ setTimeout(() => {
40
+ resolve();
41
+ }, 500);
42
+ }),
43
+ );
44
+ vi.advanceTimersByTime(300);
45
+ // 涉及到promise,等待一次tick
46
+ await Promise.resolve();
47
+ expect(barrier.isOpen()).toBe(false);
48
+ });
49
+
50
+ // reject,没有扭转
51
+ it('makeBarrierByPromise3', async () => {
52
+ try {
53
+ vi.useFakeTimers();
54
+ const barrier = makeBarrierByPromise(
55
+ expect(
56
+ new Promise<void>((resolve, reject) => {
57
+ setTimeout(() => {
58
+ reject(new Error('123'));
59
+ }, 300);
60
+ }),
61
+ ).rejects.toThrow(new Error('123')),
62
+ );
63
+ vi.advanceTimersByTime(400);
64
+ // 涉及到promise,等待一次tick
65
+ await Promise.resolve();
66
+ expect(barrier.isOpen()).toBe(false);
67
+ } catch (error) {}
68
+ });
69
+
70
+ // reject,进行扭转
71
+ it('makeBarrierByPromise4', async () => {
72
+ try {
73
+ vi.useFakeTimers();
74
+ const barrier = makeBarrierByPromise(
75
+ expect(
76
+ new Promise<void>((resolve, reject) => {
77
+ setTimeout(() => {
78
+ reject(new Error('123'));
79
+ }, 300);
80
+ }),
81
+ ).rejects.toThrow(new Error('123')),
82
+ true,
83
+ );
84
+ vi.advanceTimersByTime(400);
85
+ // 涉及到promise,等待一次tick
86
+ await Promise.resolve();
87
+ expect(barrier.isOpen()).toBe(true);
88
+ } catch (error) {}
89
+ });
90
+ });
@@ -0,0 +1,58 @@
1
+ export interface IBarrier {
2
+ isOpen: () => boolean;
3
+ open: () => void;
4
+ wait: () => Promise<boolean>;
5
+ }
6
+
7
+ /**
8
+ * A barrier that is initially closed and then becomes opened permanently after a certain period of
9
+ * time or when open is called explicitly
10
+ */
11
+ export class Barrier {
12
+ private _isOpen: boolean;
13
+ private readonly _promise: Promise<boolean>;
14
+ private _completePromise!: (v: boolean) => void;
15
+ private _rejectPromise!: (e: unknown) => void;
16
+
17
+ constructor() {
18
+ this._isOpen = false;
19
+ this._promise = new Promise<boolean>((c, e) => {
20
+ this._completePromise = c;
21
+ this._rejectPromise = e;
22
+ });
23
+ }
24
+
25
+ isOpen(): boolean {
26
+ return this._isOpen;
27
+ }
28
+
29
+ open(): void {
30
+ this._isOpen = true;
31
+ this._completePromise(true);
32
+ }
33
+
34
+ reject(e: unknown): void {
35
+ this._rejectPromise(e);
36
+ }
37
+
38
+ wait(): Promise<boolean> {
39
+ return this._promise;
40
+ }
41
+ }
42
+
43
+ export function makeBarrierByPromise(promise: Promise<any>, openWhenReject: boolean = false) {
44
+ const barrier = new Barrier();
45
+
46
+ promise
47
+ .then(() => barrier.open())
48
+ .catch((err) => {
49
+ if (openWhenReject) {
50
+ barrier.open();
51
+ throw err;
52
+ } else {
53
+ barrier.reject(err);
54
+ }
55
+ });
56
+
57
+ return barrier;
58
+ }
@@ -0,0 +1,85 @@
1
+ import type { ICancellationToken } from './cancellation';
2
+ import { CancellationTokenSource } from './cancellation';
3
+
4
+ vi.useFakeTimers();
5
+ vi.spyOn(global, 'setTimeout');
6
+ vi.spyOn(global, 'clearTimeout');
7
+
8
+ function mockFetchData(token: ICancellationToken, mockTime: number) {
9
+ return new Promise((resolve, reject) => {
10
+ setTimeout(() => {
11
+ resolve(true);
12
+ }, 4000);
13
+ token.onCancellationRequested(() => {
14
+ resolve(false);
15
+ });
16
+ vi.advanceTimersByTime(mockTime);
17
+ });
18
+ }
19
+
20
+ describe('CancellationToken', () => {
21
+ it('token cancelled', async () => {
22
+ const tokenSource = new CancellationTokenSource();
23
+ const { token } = tokenSource;
24
+ tokenSource.cancel();
25
+ const result = await mockFetchData(token, 0);
26
+ expect(result).toBe(false);
27
+ });
28
+
29
+ it('token cancel when waiting', async () => {
30
+ const tokenSource = new CancellationTokenSource();
31
+ const { token } = tokenSource;
32
+ setTimeout(() => {
33
+ tokenSource.cancel();
34
+ }, 1000);
35
+ const result = await mockFetchData(token, 1000);
36
+ expect(result).toBe(false);
37
+ });
38
+
39
+ it('fetch success', async () => {
40
+ const tokenSource = new CancellationTokenSource();
41
+ const { token } = tokenSource;
42
+ setTimeout(() => {
43
+ tokenSource.cancel();
44
+ }, 5000);
45
+ const result = await mockFetchData(token, 4000);
46
+ expect(result).toBe(true);
47
+ });
48
+
49
+ /**
50
+ * 取消前先获取signal
51
+ */
52
+ it('signal change1', async () => {
53
+ const tokenSource = new CancellationTokenSource();
54
+ const { signal, token } = tokenSource;
55
+ expect(signal.aborted).toBe(false);
56
+ setTimeout(() => {
57
+ tokenSource.cancel();
58
+ }, 1000);
59
+ await mockFetchData(token, 4000);
60
+ expect(signal.aborted).toBe(true);
61
+ });
62
+
63
+ /**
64
+ * 取消后再获取signal
65
+ */
66
+ it('signal change2', async () => {
67
+ const tokenSource = new CancellationTokenSource();
68
+ const { token } = tokenSource;
69
+ setTimeout(() => {
70
+ tokenSource.cancel();
71
+ }, 1000);
72
+ await mockFetchData(token, 4000);
73
+ expect(tokenSource.signal.aborted).toBe(true);
74
+ });
75
+
76
+ it('reason', async () => {
77
+ const tokenSource = new CancellationTokenSource();
78
+ const { token } = tokenSource;
79
+ setTimeout(() => {
80
+ tokenSource.cancel('unknown');
81
+ }, 1000);
82
+ await mockFetchData(token, 4000);
83
+ expect(token.reason).toBe('unknown');
84
+ });
85
+ });
@@ -0,0 +1,193 @@
1
+ import { EmptyDispose, type IDisposable } from '@/dispose';
2
+ import type { Event } from '@/event';
3
+ import { Emitter } from '@/event';
4
+
5
+ //
6
+ // 任何可取消的异步调用 的令牌接口
7
+ // 因为异步调用无法真正意义上取消,但是可以在异步任务的回调中增加该令牌作为参数
8
+ // 以便在操作被取消时停止执行
9
+ //
10
+ export interface ICancellationToken {
11
+ // 标记是否进行过了cancel
12
+ readonly isCancellationRequested: boolean;
13
+
14
+ // 取消的原因
15
+ readonly reason?: string;
16
+
17
+ // 令牌调用cancel后触发的回调
18
+ // 有如下特点
19
+ // 1. 只会触发一次
20
+ // 2. 当监听的时候token已经cancelled,仍然会触发一次
21
+ readonly onCancellationRequested: (
22
+ listener: () => any,
23
+ thisArgs?: any,
24
+ disposables?: IDisposable[],
25
+ ) => IDisposable;
26
+ }
27
+
28
+ //
29
+ // 编译时常量,一个快捷的事件响应
30
+ // 用于当外界监听令牌取消时,直接触发回调
31
+ //
32
+ const shortcutEvent: Event<[]> = Object.freeze(function (callback, context?): IDisposable {
33
+ const handle = setTimeout(callback.bind(context), 0);
34
+
35
+ return {
36
+ dispose() {
37
+ clearTimeout(handle);
38
+ },
39
+ };
40
+ });
41
+
42
+ //
43
+ // 可取消异步调用的令牌实现
44
+ // 默认是未取消状态,可以调用cancel进行取消
45
+ //
46
+ class MutableToken implements ICancellationToken, IDisposable {
47
+ // 是否已经取消该异步调用
48
+ private _isCancelled = false;
49
+ private _emitter: Emitter<[]> | null = null;
50
+ private _reason?: string;
51
+
52
+ public get reason(): undefined | string {
53
+ return this._reason;
54
+ }
55
+
56
+ // 获取当前是否已经取消该异步调用
57
+ public get isCancellationRequested(): boolean {
58
+ return this._isCancelled;
59
+ }
60
+
61
+ // 外界可以监听异步取消发起
62
+ public get onCancellationRequested(): Event<[]> {
63
+ if (this._isCancelled) {
64
+ return shortcutEvent;
65
+ }
66
+ if (!this._emitter) {
67
+ this._emitter = new Emitter<[]>();
68
+ }
69
+ return this._emitter.event;
70
+ }
71
+
72
+ public cancel(reason?: string) {
73
+ if (!this._isCancelled) {
74
+ this._reason = reason;
75
+ this._isCancelled = true;
76
+ if (this._emitter) {
77
+ this._emitter.fire();
78
+ this.dispose();
79
+ }
80
+ }
81
+ }
82
+
83
+ public dispose(): void {
84
+ if (this._emitter) {
85
+ this._emitter.dispose();
86
+ this._emitter = null;
87
+ }
88
+ }
89
+ }
90
+
91
+ //
92
+ // 编译期提供的一些常量Token
93
+ // 不可修改
94
+ //
95
+ // eslint-disable-next-line unicorn/no-static-only-class, @typescript-eslint/no-extraneous-class
96
+ export class CancellationToken {
97
+ static None = Object.freeze<ICancellationToken>({
98
+ isCancellationRequested: false,
99
+ onCancellationRequested: () => EmptyDispose,
100
+ });
101
+
102
+ static Cancelled = Object.freeze<ICancellationToken>({
103
+ isCancellationRequested: true,
104
+ onCancellationRequested: shortcutEvent,
105
+ });
106
+
107
+ static Make = (reason: string) => {
108
+ return Object.freeze<ICancellationToken>({
109
+ isCancellationRequested: true,
110
+ onCancellationRequested: shortcutEvent,
111
+ reason,
112
+ });
113
+ };
114
+ }
115
+
116
+ //
117
+ // 任何可取消的异步调用 的控制类
118
+ // 参考ICancellationToken,我们通过在异步调用的回调中添加token参数来判断异步调用的状态
119
+ // token来源于CancellationTokenSource
120
+ // CancellationTokenSource也会暴露cancel的接口
121
+ //
122
+ // 使用方式
123
+ // const tokenSource = new CancellationTokenSource();
124
+ //
125
+ // asyncCall(() => {
126
+ // if (token.isCancellationRequested) { return; } // 如果cancelled
127
+ // doSomething();
128
+ // });
129
+ //
130
+ // tokenSource.cancel(); // 因为某些情况,可能会cancel
131
+ // tokenSource.dispose(); // dispose时一定会cancel
132
+ //
133
+ export class CancellationTokenSource implements IDisposable {
134
+ // 真正的token
135
+ private _token?: ICancellationToken = undefined;
136
+ // 可能存在父级CancellationTokenSource
137
+ private readonly _parentListener?: IDisposable = undefined;
138
+ // 为了支持signal场景,所以在需要时会初始化浏览器提供的abortController原生结构
139
+ private _abortController?: AbortController = undefined;
140
+
141
+ constructor(parent?: ICancellationToken) {
142
+ // 如果存在父级,当父对象cancel时,子对象也必须cancel
143
+ this._parentListener = parent?.onCancellationRequested(this.cancel, this);
144
+ }
145
+
146
+ /**
147
+ * 传统的cancellation用法
148
+ */
149
+ public get token(): ICancellationToken {
150
+ if (!this._token) {
151
+ this._token = new MutableToken();
152
+ }
153
+ return this._token;
154
+ }
155
+
156
+ /**
157
+ * 对齐浏览器提供的abortSignal,支持给fetch、axios等传参使用
158
+ */
159
+ public get signal(): AbortSignal {
160
+ if (this._abortController) {
161
+ return this._abortController.signal;
162
+ }
163
+ this._abortController = new AbortController();
164
+ if (this._token?.isCancellationRequested) {
165
+ this._abortController.abort();
166
+ }
167
+ return this._abortController.signal;
168
+ }
169
+
170
+ public cancel(reason?: string): void {
171
+ if (!this._token) {
172
+ // 如果没有使用过token就直接cancel,那么就返回一个常量即可
173
+ this._token = reason === undefined ? CancellationToken.Cancelled : CancellationToken.Make(reason);
174
+ } else if (this._token instanceof MutableToken) {
175
+ this._token.cancel(reason);
176
+ }
177
+ if (this._abortController) {
178
+ this._abortController.abort(reason);
179
+ }
180
+ }
181
+
182
+ public dispose(cancel = false): void {
183
+ if (cancel) {
184
+ this.cancel();
185
+ }
186
+ this._parentListener?.dispose();
187
+ if (!this._token) {
188
+ this._token = CancellationToken.None;
189
+ } else if (this._token instanceof MutableToken) {
190
+ this._token.dispose();
191
+ }
192
+ }
193
+ }
@@ -0,0 +1,18 @@
1
+ // 异步任务可取消的token
2
+ export type { ICancellationToken } from './cancellation';
3
+ // 异步任务可取消的源
4
+ export { CancellationTokenSource } from './cancellation';
5
+
6
+ // 通用的wait函数,提供异步等待能力
7
+ export { wait, sleep } from './wait';
8
+
9
+ // 提供调用 open 后 resolve promise 的能力
10
+ export { Barrier } from './barrier';
11
+ export { makeBarrierByPromise } from './barrier';
12
+
13
+ // 提供异步队列控制器
14
+ export { AsyncQueue } from './queue/queue';
15
+ export type { IAsyncTask } from './queue/task';
16
+
17
+ // 下一次eventloop再执行方法
18
+ export { invokeNextLoop } from './utils';