@planet-matrix/mobius-model 0.5.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +123 -36
  3. package/dist/index.js +715 -4
  4. package/dist/index.js.map +981 -13
  5. package/oxlint.config.ts +6 -0
  6. package/package.json +36 -18
  7. package/src/abort/README.md +92 -0
  8. package/src/abort/abort-manager.ts +278 -0
  9. package/src/abort/abort-signal-listener-manager.ts +81 -0
  10. package/src/abort/index.ts +2 -0
  11. package/src/ai/README.md +1 -0
  12. package/src/ai/ai.ts +107 -0
  13. package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
  14. package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
  15. package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
  16. package/src/ai/chat-completion-ai/index.ts +7 -0
  17. package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
  18. package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
  19. package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
  20. package/src/ai/embedding-ai/embedding-ai.ts +63 -0
  21. package/src/ai/embedding-ai/embedding.ts +50 -0
  22. package/src/ai/embedding-ai/index.ts +4 -0
  23. package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
  24. package/src/ai/index.ts +4 -0
  25. package/src/aio/README.md +100 -0
  26. package/src/aio/content.ts +141 -0
  27. package/src/aio/index.ts +3 -0
  28. package/src/aio/json.ts +127 -0
  29. package/src/aio/prompt.ts +246 -0
  30. package/src/basic/README.md +72 -116
  31. package/src/basic/error.ts +19 -5
  32. package/src/basic/function.ts +83 -64
  33. package/src/basic/index.ts +1 -0
  34. package/src/basic/is.ts +152 -71
  35. package/src/basic/promise.ts +29 -8
  36. package/src/basic/schedule.ts +111 -0
  37. package/src/basic/stream.ts +135 -25
  38. package/src/basic/string.ts +2 -33
  39. package/src/color/README.md +105 -0
  40. package/src/color/index.ts +3 -0
  41. package/src/color/internal.ts +42 -0
  42. package/src/color/rgb/analyze.ts +236 -0
  43. package/src/color/rgb/construct.ts +130 -0
  44. package/src/color/rgb/convert.ts +227 -0
  45. package/src/color/rgb/derive.ts +303 -0
  46. package/src/color/rgb/index.ts +6 -0
  47. package/src/color/rgb/internal.ts +208 -0
  48. package/src/color/rgb/parse.ts +302 -0
  49. package/src/color/rgb/serialize.ts +144 -0
  50. package/src/color/types.ts +57 -0
  51. package/src/color/xyz/analyze.ts +80 -0
  52. package/src/color/xyz/construct.ts +19 -0
  53. package/src/color/xyz/convert.ts +71 -0
  54. package/src/color/xyz/index.ts +3 -0
  55. package/src/color/xyz/internal.ts +23 -0
  56. package/src/credential/README.md +107 -0
  57. package/src/credential/api-key.ts +158 -0
  58. package/src/credential/bearer.ts +73 -0
  59. package/src/credential/index.ts +4 -0
  60. package/src/credential/json-web-token.ts +96 -0
  61. package/src/credential/password.ts +170 -0
  62. package/src/cron/README.md +86 -0
  63. package/src/cron/cron.ts +87 -0
  64. package/src/cron/index.ts +1 -0
  65. package/src/css/README.md +93 -0
  66. package/src/css/class.ts +559 -0
  67. package/src/css/index.ts +1 -0
  68. package/src/drizzle/README.md +1 -0
  69. package/src/drizzle/drizzle.ts +1 -0
  70. package/src/drizzle/helper.ts +47 -0
  71. package/src/drizzle/index.ts +5 -0
  72. package/src/drizzle/infer.ts +52 -0
  73. package/src/drizzle/kysely.ts +8 -0
  74. package/src/drizzle/pagination.ts +200 -0
  75. package/src/email/README.md +1 -0
  76. package/src/email/index.ts +1 -0
  77. package/src/email/resend.ts +25 -0
  78. package/src/encoding/README.md +66 -79
  79. package/src/encoding/base64.ts +13 -4
  80. package/src/environment/README.md +97 -0
  81. package/src/environment/basic.ts +26 -0
  82. package/src/environment/device.ts +311 -0
  83. package/src/environment/feature.ts +285 -0
  84. package/src/environment/geo.ts +337 -0
  85. package/src/environment/index.ts +7 -0
  86. package/src/environment/runtime.ts +400 -0
  87. package/src/environment/snapshot.ts +60 -0
  88. package/src/environment/variable.ts +239 -0
  89. package/src/event/README.md +90 -0
  90. package/src/event/class-event-proxy.ts +229 -0
  91. package/src/event/common.ts +29 -0
  92. package/src/event/event-manager.ts +203 -0
  93. package/src/event/index.ts +4 -0
  94. package/src/event/instance-event-proxy.ts +187 -0
  95. package/src/event/internal.ts +24 -0
  96. package/src/exception/README.md +96 -0
  97. package/src/exception/browser.ts +219 -0
  98. package/src/exception/index.ts +4 -0
  99. package/src/exception/nodejs.ts +169 -0
  100. package/src/exception/normalize.ts +106 -0
  101. package/src/exception/types.ts +99 -0
  102. package/src/form/README.md +25 -0
  103. package/src/form/index.ts +1 -0
  104. package/src/form/inputor-controller/base.ts +874 -0
  105. package/src/form/inputor-controller/boolean.ts +39 -0
  106. package/src/form/inputor-controller/file.ts +39 -0
  107. package/src/form/inputor-controller/form.ts +181 -0
  108. package/src/form/inputor-controller/helper.ts +117 -0
  109. package/src/form/inputor-controller/index.ts +17 -0
  110. package/src/form/inputor-controller/multi-select.ts +99 -0
  111. package/src/form/inputor-controller/number.ts +116 -0
  112. package/src/form/inputor-controller/select.ts +109 -0
  113. package/src/form/inputor-controller/text.ts +82 -0
  114. package/src/http/READMD.md +1 -0
  115. package/src/http/api/api-core.ts +84 -0
  116. package/src/http/api/api-handler.ts +79 -0
  117. package/src/http/api/api-host.ts +47 -0
  118. package/src/http/api/api-result.ts +56 -0
  119. package/src/http/api/api-schema.ts +154 -0
  120. package/src/http/api/api-server.ts +130 -0
  121. package/src/http/api/api-test.ts +142 -0
  122. package/src/http/api/api-type.ts +37 -0
  123. package/src/http/api/api.ts +81 -0
  124. package/src/http/api/index.ts +11 -0
  125. package/src/http/api-adapter/api-core-node-http.ts +260 -0
  126. package/src/http/api-adapter/api-host-node-http.ts +156 -0
  127. package/src/http/api-adapter/api-result-arktype.ts +297 -0
  128. package/src/http/api-adapter/api-result-zod.ts +286 -0
  129. package/src/http/api-adapter/index.ts +5 -0
  130. package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
  131. package/src/http/bin/gen-api-list/index.ts +1 -0
  132. package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
  133. package/src/http/bin/gen-api-test/index.ts +1 -0
  134. package/src/http/bin/gen-api-type/calc-code.ts +25 -0
  135. package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
  136. package/src/http/bin/gen-api-type/index.ts +2 -0
  137. package/src/http/bin/index.ts +2 -0
  138. package/src/http/index.ts +3 -0
  139. package/src/huawei/README.md +1 -0
  140. package/src/huawei/index.ts +2 -0
  141. package/src/huawei/moderation/index.ts +1 -0
  142. package/src/huawei/moderation/moderation.ts +355 -0
  143. package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
  144. package/src/huawei/obs/index.ts +1 -0
  145. package/src/huawei/obs/obs.ts +42 -0
  146. package/src/identifier/README.md +92 -0
  147. package/src/identifier/id.ts +119 -0
  148. package/src/identifier/index.ts +2 -0
  149. package/src/identifier/uuid.ts +187 -0
  150. package/src/index.ts +33 -1
  151. package/src/json/README.md +92 -0
  152. package/src/json/index.ts +1 -0
  153. package/src/json/repair.ts +18 -0
  154. package/src/log/README.md +79 -0
  155. package/src/log/index.ts +5 -0
  156. package/src/log/log-emitter.ts +72 -0
  157. package/src/log/log-record.ts +10 -0
  158. package/src/log/log-scheduler.ts +74 -0
  159. package/src/log/log-type.ts +8 -0
  160. package/src/log/logger.ts +554 -0
  161. package/src/openai/README.md +1 -0
  162. package/src/openai/index.ts +1 -0
  163. package/src/openai/openai.ts +510 -0
  164. package/src/orchestration/README.md +91 -0
  165. package/src/orchestration/coordination/barrier.ts +214 -0
  166. package/src/orchestration/coordination/count-down-latch.ts +215 -0
  167. package/src/orchestration/coordination/errors.ts +98 -0
  168. package/src/orchestration/coordination/index.ts +16 -0
  169. package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
  170. package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
  171. package/src/orchestration/coordination/keyed-lock.ts +168 -0
  172. package/src/orchestration/coordination/mutex.ts +257 -0
  173. package/src/orchestration/coordination/permit.ts +127 -0
  174. package/src/orchestration/coordination/read-write-lock.ts +444 -0
  175. package/src/orchestration/coordination/semaphore.ts +280 -0
  176. package/src/orchestration/dispatching/dispatcher.ts +83 -0
  177. package/src/orchestration/dispatching/index.ts +2 -0
  178. package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
  179. package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
  180. package/src/orchestration/dispatching/selector/index.ts +2 -0
  181. package/src/orchestration/index.ts +3 -0
  182. package/src/orchestration/scheduling/index.ts +2 -0
  183. package/src/orchestration/scheduling/scheduler.ts +103 -0
  184. package/src/orchestration/scheduling/task.ts +32 -0
  185. package/src/random/README.md +56 -86
  186. package/src/random/base.ts +66 -0
  187. package/src/random/index.ts +5 -1
  188. package/src/random/random-boolean.ts +40 -0
  189. package/src/random/random-integer.ts +60 -0
  190. package/src/random/random-number.ts +72 -0
  191. package/src/random/random-string.ts +66 -0
  192. package/src/reactor/README.md +4 -0
  193. package/src/reactor/reactor-core/primitive.ts +9 -9
  194. package/src/reactor/reactor-core/reactive-system.ts +5 -5
  195. package/src/request/README.md +108 -0
  196. package/src/request/fetch/base.ts +108 -0
  197. package/src/request/fetch/browser.ts +285 -0
  198. package/src/request/fetch/general.ts +20 -0
  199. package/src/request/fetch/index.ts +4 -0
  200. package/src/request/fetch/nodejs.ts +285 -0
  201. package/src/request/index.ts +2 -0
  202. package/src/request/request/base.ts +250 -0
  203. package/src/request/request/general.ts +64 -0
  204. package/src/request/request/index.ts +3 -0
  205. package/src/request/request/resource.ts +68 -0
  206. package/src/result/README.md +4 -0
  207. package/src/result/controller.ts +54 -0
  208. package/src/result/either.ts +193 -0
  209. package/src/result/index.ts +2 -0
  210. package/src/route/README.md +105 -0
  211. package/src/route/adapter/browser.ts +122 -0
  212. package/src/route/adapter/driver.ts +56 -0
  213. package/src/route/adapter/index.ts +2 -0
  214. package/src/route/index.ts +3 -0
  215. package/src/route/router/index.ts +2 -0
  216. package/src/route/router/route.ts +630 -0
  217. package/src/route/router/router.ts +1642 -0
  218. package/src/route/uri/hash.ts +308 -0
  219. package/src/route/uri/index.ts +7 -0
  220. package/src/route/uri/pathname.ts +376 -0
  221. package/src/route/uri/search.ts +413 -0
  222. package/src/singleton/README.md +79 -0
  223. package/src/singleton/factory.ts +55 -0
  224. package/src/singleton/index.ts +2 -0
  225. package/src/singleton/manager.ts +204 -0
  226. package/src/socket/README.md +105 -0
  227. package/src/socket/client/index.ts +2 -0
  228. package/src/socket/client/socket-unit.ts +660 -0
  229. package/src/socket/client/socket.ts +203 -0
  230. package/src/socket/common/index.ts +2 -0
  231. package/src/socket/common/socket-unit-common.ts +23 -0
  232. package/src/socket/common/socket-unit-heartbeat.ts +427 -0
  233. package/src/socket/index.ts +3 -0
  234. package/src/socket/server/index.ts +3 -0
  235. package/src/socket/server/server.ts +183 -0
  236. package/src/socket/server/socket-unit.ts +449 -0
  237. package/src/socket/server/socket.ts +264 -0
  238. package/src/storage/README.md +107 -0
  239. package/src/storage/index.ts +1 -0
  240. package/src/storage/table.ts +449 -0
  241. package/src/timer/README.md +86 -0
  242. package/src/timer/expiration/expiration-manager.ts +594 -0
  243. package/src/timer/expiration/index.ts +3 -0
  244. package/src/timer/expiration/min-heap.ts +208 -0
  245. package/src/timer/expiration/remaining-manager.ts +241 -0
  246. package/src/timer/index.ts +1 -0
  247. package/src/tube/README.md +99 -0
  248. package/src/tube/helper.ts +138 -0
  249. package/src/tube/index.ts +2 -0
  250. package/src/tube/tube.ts +880 -0
  251. package/src/type/README.md +54 -307
  252. package/src/type/class.ts +2 -2
  253. package/src/type/index.ts +14 -14
  254. package/src/type/is.ts +265 -2
  255. package/src/type/object.ts +37 -0
  256. package/src/type/string.ts +7 -2
  257. package/src/type/tuple.ts +6 -6
  258. package/src/type/union.ts +16 -0
  259. package/src/web/README.md +77 -0
  260. package/src/web/capture.ts +35 -0
  261. package/src/web/clipboard.ts +97 -0
  262. package/src/web/dom.ts +117 -0
  263. package/src/web/download.ts +16 -0
  264. package/src/web/event.ts +46 -0
  265. package/src/web/index.ts +10 -0
  266. package/src/web/local-storage.ts +113 -0
  267. package/src/web/location.ts +28 -0
  268. package/src/web/permission.ts +172 -0
  269. package/src/web/script-loader.ts +432 -0
  270. package/src/weixin/README.md +1 -0
  271. package/src/weixin/index.ts +2 -0
  272. package/src/weixin/official-account/authorization.ts +159 -0
  273. package/src/weixin/official-account/index.ts +2 -0
  274. package/src/weixin/official-account/js-api.ts +134 -0
  275. package/src/weixin/open/index.ts +1 -0
  276. package/src/weixin/open/oauth2.ts +133 -0
  277. package/tests/unit/abort/abort-manager.spec.ts +225 -0
  278. package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
  279. package/tests/unit/ai/ai.spec.ts +85 -0
  280. package/tests/unit/aio/content.spec.ts +105 -0
  281. package/tests/unit/aio/json.spec.ts +147 -0
  282. package/tests/unit/aio/prompt.spec.ts +111 -0
  283. package/tests/unit/basic/array.spec.ts +1 -1
  284. package/tests/unit/basic/error.spec.ts +16 -4
  285. package/tests/unit/basic/schedule.spec.ts +74 -0
  286. package/tests/unit/basic/stream.spec.ts +91 -38
  287. package/tests/unit/basic/string.spec.ts +0 -9
  288. package/tests/unit/color/rgb/analyze.spec.ts +110 -0
  289. package/tests/unit/color/rgb/construct.spec.ts +56 -0
  290. package/tests/unit/color/rgb/convert.spec.ts +60 -0
  291. package/tests/unit/color/rgb/derive.spec.ts +103 -0
  292. package/tests/unit/color/rgb/parse.spec.ts +66 -0
  293. package/tests/unit/color/rgb/serialize.spec.ts +46 -0
  294. package/tests/unit/color/xyz/analyze.spec.ts +33 -0
  295. package/tests/unit/color/xyz/construct.spec.ts +10 -0
  296. package/tests/unit/color/xyz/convert.spec.ts +18 -0
  297. package/tests/unit/credential/api-key.spec.ts +37 -0
  298. package/tests/unit/credential/bearer.spec.ts +23 -0
  299. package/tests/unit/credential/json-web-token.spec.ts +23 -0
  300. package/tests/unit/credential/password.spec.ts +41 -0
  301. package/tests/unit/cron/cron.spec.ts +84 -0
  302. package/tests/unit/css/class.spec.ts +157 -0
  303. package/tests/unit/environment/basic.spec.ts +20 -0
  304. package/tests/unit/environment/device.spec.ts +146 -0
  305. package/tests/unit/environment/feature.spec.ts +388 -0
  306. package/tests/unit/environment/geo.spec.ts +111 -0
  307. package/tests/unit/environment/runtime.spec.ts +364 -0
  308. package/tests/unit/environment/snapshot.spec.ts +4 -0
  309. package/tests/unit/environment/variable.spec.ts +190 -0
  310. package/tests/unit/event/class-event-proxy.spec.ts +225 -0
  311. package/tests/unit/event/event-manager.spec.ts +246 -0
  312. package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
  313. package/tests/unit/exception/browser.spec.ts +213 -0
  314. package/tests/unit/exception/nodejs.spec.ts +144 -0
  315. package/tests/unit/exception/normalize.spec.ts +57 -0
  316. package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
  317. package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
  318. package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
  319. package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
  320. package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
  321. package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
  322. package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
  323. package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
  324. package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
  325. package/tests/unit/http/api/api-core-host.spec.ts +207 -0
  326. package/tests/unit/http/api/api-schema.spec.ts +120 -0
  327. package/tests/unit/http/api/api-server.spec.ts +363 -0
  328. package/tests/unit/http/api/api-test.spec.ts +117 -0
  329. package/tests/unit/http/api/api.spec.ts +121 -0
  330. package/tests/unit/http/api-adapter/node-http.spec.ts +191 -0
  331. package/tests/unit/identifier/id.spec.ts +71 -0
  332. package/tests/unit/identifier/uuid.spec.ts +85 -0
  333. package/tests/unit/json/repair.spec.ts +11 -0
  334. package/tests/unit/log/log-emitter.spec.ts +33 -0
  335. package/tests/unit/log/log-scheduler.spec.ts +40 -0
  336. package/tests/unit/log/log-type.spec.ts +7 -0
  337. package/tests/unit/log/logger.spec.ts +237 -0
  338. package/tests/unit/openai/openai.spec.ts +64 -0
  339. package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
  340. package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
  341. package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
  342. package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
  343. package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
  344. package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
  345. package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
  346. package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
  347. package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
  348. package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
  349. package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
  350. package/tests/unit/random/base.spec.ts +58 -0
  351. package/tests/unit/random/random-boolean.spec.ts +25 -0
  352. package/tests/unit/random/random-integer.spec.ts +32 -0
  353. package/tests/unit/random/random-number.spec.ts +33 -0
  354. package/tests/unit/random/random-string.spec.ts +22 -0
  355. package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
  356. package/tests/unit/reactor/preact-signal.spec.ts +1 -2
  357. package/tests/unit/request/fetch/browser.spec.ts +222 -0
  358. package/tests/unit/request/fetch/general.spec.ts +43 -0
  359. package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
  360. package/tests/unit/request/request/base.spec.ts +385 -0
  361. package/tests/unit/request/request/general.spec.ts +161 -0
  362. package/tests/unit/route/router/route.spec.ts +431 -0
  363. package/tests/unit/route/router/router.spec.ts +407 -0
  364. package/tests/unit/route/uri/hash.spec.ts +72 -0
  365. package/tests/unit/route/uri/pathname.spec.ts +147 -0
  366. package/tests/unit/route/uri/search.spec.ts +107 -0
  367. package/tests/unit/singleton/singleton.spec.ts +49 -0
  368. package/tests/unit/socket/client.spec.ts +208 -0
  369. package/tests/unit/socket/server.spec.ts +135 -0
  370. package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
  371. package/tests/unit/storage/table.spec.ts +620 -0
  372. package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
  373. package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
  374. package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
  375. package/tests/unit/tube/helper.spec.ts +139 -0
  376. package/tests/unit/tube/tube.spec.ts +501 -0
  377. package/.oxlintrc.json +0 -5
  378. package/src/random/uuid.ts +0 -103
  379. package/tests/unit/random/uuid.spec.ts +0 -37
@@ -0,0 +1,458 @@
1
+ import { expect, test, vi } from "vitest"
2
+
3
+ import type {
4
+ BaseInputorContext,
5
+ BaseInputorControllerOptions,
6
+ BaseInputorSchema,
7
+ } from "#Source/form/index.ts"
8
+ import { BaseInputorController } from "#Source/form/index.ts"
9
+
10
+ const TEST_INPUTOR_TYPE_NAME = "test" as const
11
+
12
+ type TestExternalValue = string | undefined
13
+ type TestInternalValue = string | undefined
14
+
15
+ interface TestInputorSchema extends BaseInputorSchema<TestExternalValue> {
16
+ inputorTypeName: typeof TEST_INPUTOR_TYPE_NAME
17
+ }
18
+
19
+ interface TestInputorContext extends BaseInputorContext<TestExternalValue, TestInternalValue> {
20
+ }
21
+
22
+ interface TestInputorControllerOptions extends BaseInputorControllerOptions<TestExternalValue, TestInputorSchema> {
23
+ }
24
+
25
+ class TestInputorController extends BaseInputorController<
26
+ TestExternalValue,
27
+ TestInternalValue,
28
+ TestInputorSchema,
29
+ TestInputorContext
30
+ > {
31
+ declare schemaType: TestInputorSchema
32
+ declare optionsType: TestInputorControllerOptions
33
+ declare constructorType: typeof TestInputorController
34
+
35
+ static inputorTypeName = TEST_INPUTOR_TYPE_NAME
36
+
37
+ inputorTypeName = TEST_INPUTOR_TYPE_NAME
38
+ protected voidExternalValue = undefined
39
+ protected voidInternalValue = undefined
40
+
41
+ protected override async constrainExternalValue(value: TestExternalValue): Promise<TestExternalValue> {
42
+ if (value === undefined) {
43
+ return await Promise.resolve(undefined)
44
+ }
45
+ return await Promise.resolve(value.trim())
46
+ }
47
+
48
+ protected override async constrainInternalValue(value: TestInternalValue): Promise<TestInternalValue> {
49
+ if (value === undefined) {
50
+ return await Promise.resolve(undefined)
51
+ }
52
+ return await Promise.resolve(value.trim())
53
+ }
54
+ }
55
+
56
+ const createTestInputor = (
57
+ overrides: Partial<TestInputorControllerOptions> = {},
58
+ ): TestInputorController => {
59
+ return new TestInputorController({
60
+ id: "test-id",
61
+ name: "test-name",
62
+ placeholder: "test-placeholder",
63
+ value: " initial ",
64
+ ...overrides,
65
+ })
66
+ }
67
+
68
+ test("BaseInputorController.isReady and waitForReady initialize defaults and emit initial hooks", async () => {
69
+ const valueChanges: Array<{ newValue: TestExternalValue; oldValue: TestExternalValue }> = []
70
+ const schemaChanges: Array<{ newSchema: TestInputorSchema; oldSchema: TestInputorSchema }> = []
71
+ const controller = createTestInputor({
72
+ onValueChange: (context) => {
73
+ valueChanges.push(context)
74
+ },
75
+ onSchemaChange: (context) => {
76
+ schemaChanges.push(context)
77
+ },
78
+ })
79
+
80
+ expect(controller.isReady()).toBe(false)
81
+
82
+ await controller.waitForReady()
83
+
84
+ expect(controller.isReady()).toBe(true)
85
+ expect(await controller.getSchema()).toEqual({
86
+ inputorTypeName: TEST_INPUTOR_TYPE_NAME,
87
+ id: "test-id",
88
+ name: "test-name",
89
+ placeholder: "test-placeholder",
90
+ value: "initial",
91
+ isVoid: false,
92
+ isFocused: false,
93
+ isTouched: false,
94
+ isDirty: false,
95
+ isDisabled: false,
96
+ isDebugMode: false,
97
+ })
98
+ expect(valueChanges).toEqual([
99
+ {
100
+ newValue: "initial",
101
+ oldValue: "initial",
102
+ },
103
+ ])
104
+ expect(schemaChanges).toHaveLength(1)
105
+ expect(schemaChanges[0]!.newSchema).toEqual(schemaChanges[0]!.oldSchema)
106
+ expect(schemaChanges[0]!.newSchema.value).toBe("initial")
107
+ })
108
+
109
+ test("BaseInputorController.getInternalValue, getContext, and isEqualSchema expose current state", async () => {
110
+ const controller = createTestInputor({
111
+ value: " alpha ",
112
+ })
113
+
114
+ await controller.waitForReady()
115
+
116
+ expect(controller.getInternalValue()).toBe("alpha")
117
+ expect(await controller.getContext()).toEqual({
118
+ inputorTypeName: TEST_INPUTOR_TYPE_NAME,
119
+ id: "test-id",
120
+ name: "test-name",
121
+ placeholder: "test-placeholder",
122
+ value: "alpha",
123
+ isVoid: false,
124
+ isFocused: false,
125
+ isTouched: false,
126
+ isDirty: false,
127
+ isDisabled: false,
128
+ isDebugMode: false,
129
+ internalValue: "alpha",
130
+ isReady: true,
131
+ })
132
+ expect(await controller.isEqualSchema({ value: "alpha", placeholder: "test-placeholder" })).toBe(true)
133
+ expect(await controller.isEqualSchema({ value: "beta" })).toBe(false)
134
+ expect(await controller.isEqualSchema(null)).toBe(false)
135
+ })
136
+
137
+ test("BaseInputorController.subscribeInputChange and updateInputValue emit input updates after debounce", async () => {
138
+ vi.useFakeTimers()
139
+
140
+ try {
141
+ const controller = createTestInputor({
142
+ value: "start",
143
+ inputDebounce: 20,
144
+ })
145
+ const inputChanges: Array<{ newInput: TestExternalValue; oldInput: TestExternalValue; oldValue: TestExternalValue }> = []
146
+
147
+ await controller.waitForReady()
148
+ controller.subscribeInputChange((context) => {
149
+ inputChanges.push(context)
150
+ })
151
+
152
+ await controller.updateInputValue(" next ")
153
+
154
+ expect(inputChanges).toEqual([])
155
+
156
+ await vi.advanceTimersByTimeAsync(20)
157
+
158
+ expect(inputChanges).toEqual([
159
+ {
160
+ newInput: " next ",
161
+ oldInput: "start",
162
+ oldValue: "start",
163
+ },
164
+ ])
165
+ }
166
+ finally {
167
+ vi.useRealTimers()
168
+ }
169
+ })
170
+
171
+ test("BaseInputorController.unsubscribeInputChange removes one input subscriber", async () => {
172
+ vi.useFakeTimers()
173
+
174
+ try {
175
+ const controller = createTestInputor({ value: "start" })
176
+ let calls = 0
177
+ const subscriber = (): void => {
178
+ calls = calls + 1
179
+ }
180
+
181
+ await controller.waitForReady()
182
+ controller.subscribeInputChange(subscriber)
183
+ controller.unsubscribeInputChange(subscriber)
184
+
185
+ await controller.updateInputValue("next")
186
+ await vi.advanceTimersByTimeAsync(0)
187
+
188
+ expect(calls).toBe(0)
189
+ }
190
+ finally {
191
+ vi.useRealTimers()
192
+ }
193
+ })
194
+
195
+ test("BaseInputorController.clearInputChangeSubscribers removes all input subscribers", async () => {
196
+ vi.useFakeTimers()
197
+
198
+ try {
199
+ const controller = createTestInputor({ value: "start" })
200
+ let calls = 0
201
+
202
+ await controller.waitForReady()
203
+ controller.subscribeInputChange(() => {
204
+ calls = calls + 1
205
+ })
206
+ controller.subscribeInputChange(() => {
207
+ calls = calls + 1
208
+ })
209
+ controller.clearInputChangeSubscribers()
210
+
211
+ await controller.updateInputValue("next")
212
+ await vi.advanceTimersByTimeAsync(0)
213
+
214
+ expect(calls).toBe(0)
215
+ }
216
+ finally {
217
+ vi.useRealTimers()
218
+ }
219
+ })
220
+
221
+ test("BaseInputorController.subscribeValueChange, applyInputValue, and updateValue emit value changes", async () => {
222
+ const controller = createTestInputor({ value: "start" })
223
+ const valueChanges: Array<{ newValue: TestExternalValue; oldValue: TestExternalValue }> = []
224
+
225
+ await controller.waitForReady()
226
+ controller.subscribeValueChange((context) => {
227
+ valueChanges.push(context)
228
+ })
229
+
230
+ await controller.updateInputValue(" next ")
231
+ await controller.applyInputValue()
232
+ await controller.updateValue(" final ")
233
+
234
+ expect(valueChanges).toEqual([
235
+ {
236
+ newValue: "next",
237
+ oldValue: "start",
238
+ },
239
+ {
240
+ newValue: "final",
241
+ oldValue: "next",
242
+ },
243
+ ])
244
+ })
245
+
246
+ test("BaseInputorController.unsubscribeValueChange removes one value subscriber", async () => {
247
+ const controller = createTestInputor({ value: "start" })
248
+ let calls = 0
249
+ const subscriber = (): void => {
250
+ calls = calls + 1
251
+ }
252
+
253
+ await controller.waitForReady()
254
+ controller.subscribeValueChange(subscriber)
255
+ controller.unsubscribeValueChange(subscriber)
256
+ await controller.updateValue("next")
257
+
258
+ expect(calls).toBe(0)
259
+ })
260
+
261
+ test("BaseInputorController.clearValueChangeSubscribers removes all value subscribers", async () => {
262
+ const controller = createTestInputor({ value: "start" })
263
+ let calls = 0
264
+
265
+ await controller.waitForReady()
266
+ controller.subscribeValueChange(() => {
267
+ calls = calls + 1
268
+ })
269
+ controller.subscribeValueChange(() => {
270
+ calls = calls + 1
271
+ })
272
+ controller.clearValueChangeSubscribers()
273
+ await controller.updateValue("next")
274
+
275
+ expect(calls).toBe(0)
276
+ })
277
+
278
+ test("BaseInputorController.subscribeSchemaChange and updatePlaceholder emit schema changes", async () => {
279
+ const controller = createTestInputor({ value: "start" })
280
+ const schemaChanges: Array<{ newSchema: TestInputorSchema; oldSchema: TestInputorSchema }> = []
281
+
282
+ await controller.waitForReady()
283
+ await Promise.resolve()
284
+ controller.subscribeSchemaChange((context) => {
285
+ schemaChanges.push(context)
286
+ })
287
+ await controller.updatePlaceholder("next-placeholder")
288
+
289
+ expect(schemaChanges.length).toBeGreaterThanOrEqual(1)
290
+ expect(schemaChanges.at(-1)!.oldSchema.placeholder).toBe("test-placeholder")
291
+ expect(schemaChanges.at(-1)!.newSchema.placeholder).toBe("next-placeholder")
292
+ })
293
+
294
+ test("BaseInputorController.unsubscribeSchemaChange removes one schema subscriber", async () => {
295
+ const controller = createTestInputor({ value: "start" })
296
+ let calls = 0
297
+ const subscriber = (): void => {
298
+ calls = calls + 1
299
+ }
300
+
301
+ await controller.waitForReady()
302
+ controller.subscribeSchemaChange(subscriber)
303
+ controller.unsubscribeSchemaChange(subscriber)
304
+ await controller.updatePlaceholder("next-placeholder")
305
+
306
+ expect(calls).toBe(0)
307
+ })
308
+
309
+ test("BaseInputorController.clearSchemaChangeSubscribers removes all schema subscribers", async () => {
310
+ const controller = createTestInputor({ value: "start" })
311
+ let calls = 0
312
+
313
+ await controller.waitForReady()
314
+ controller.subscribeSchemaChange(() => {
315
+ calls = calls + 1
316
+ })
317
+ controller.subscribeSchemaChange(() => {
318
+ calls = calls + 1
319
+ })
320
+ controller.clearSchemaChangeSubscribers()
321
+ await controller.updatePlaceholder("next-placeholder")
322
+
323
+ expect(calls).toBe(0)
324
+ })
325
+
326
+ test("BaseInputorController.updateIsVoid resets the value to its void value", async () => {
327
+ const controller = createTestInputor({ value: "start" })
328
+
329
+ await controller.waitForReady()
330
+ await controller.updateIsVoid(true)
331
+
332
+ expect(await controller.getSchema()).toMatchObject({
333
+ value: undefined,
334
+ isVoid: true,
335
+ isDirty: true,
336
+ })
337
+ })
338
+
339
+ test("BaseInputorController.updateIsFocused also marks the controller as touched", async () => {
340
+ const controller = createTestInputor({ value: "start" })
341
+
342
+ await controller.waitForReady()
343
+ await controller.updateIsFocused(true)
344
+
345
+ expect(await controller.getSchema()).toMatchObject({
346
+ isFocused: true,
347
+ isTouched: true,
348
+ })
349
+ })
350
+
351
+ test("BaseInputorController.updateIsTouched updates touched state directly", async () => {
352
+ const controller = createTestInputor({ value: "start" })
353
+
354
+ await controller.waitForReady()
355
+ await controller.updateIsTouched(true)
356
+
357
+ expect(await controller.getSchema()).toMatchObject({
358
+ isTouched: true,
359
+ })
360
+ })
361
+
362
+ test("BaseInputorController.updateIsDirty updates dirty state directly", async () => {
363
+ const controller = createTestInputor({ value: "start" })
364
+
365
+ await controller.waitForReady()
366
+ await controller.updateIsDirty(true)
367
+
368
+ expect(await controller.getSchema()).toMatchObject({
369
+ isDirty: true,
370
+ })
371
+ })
372
+
373
+ test("BaseInputorController.updateIsDisabled updates disabled state directly", async () => {
374
+ const controller = createTestInputor({ value: "start" })
375
+
376
+ await controller.waitForReady()
377
+ await controller.updateIsDisabled(true)
378
+
379
+ expect(await controller.getSchema()).toMatchObject({
380
+ isDisabled: true,
381
+ })
382
+ })
383
+
384
+ test("BaseInputorController.updateIsDebugMode updates debug mode directly", async () => {
385
+ const controller = createTestInputor({ value: "start" })
386
+
387
+ await controller.waitForReady()
388
+ await controller.updateIsDebugMode(true)
389
+
390
+ expect(await controller.getSchema()).toMatchObject({
391
+ isDebugMode: true,
392
+ })
393
+ })
394
+
395
+ test("BaseInputorController.updateSchema applies multiple schema fields in one pass", async () => {
396
+ const controller = createTestInputor({ value: "start" })
397
+
398
+ await controller.waitForReady()
399
+ await controller.updateSchema({
400
+ ...(await controller.getSchema()),
401
+ placeholder: "schema-placeholder",
402
+ value: " schema-value ",
403
+ isFocused: true,
404
+ isTouched: true,
405
+ isDirty: true,
406
+ isDisabled: true,
407
+ isDebugMode: true,
408
+ })
409
+
410
+ expect(await controller.getSchema()).toEqual({
411
+ inputorTypeName: TEST_INPUTOR_TYPE_NAME,
412
+ id: "test-id",
413
+ name: "test-name",
414
+ placeholder: "schema-placeholder",
415
+ value: "schema-value",
416
+ isVoid: false,
417
+ isFocused: true,
418
+ isTouched: true,
419
+ isDirty: true,
420
+ isDisabled: true,
421
+ isDebugMode: true,
422
+ })
423
+ })
424
+
425
+ test("BaseInputorController.destroy clears every subscriber collection", async () => {
426
+ vi.useFakeTimers()
427
+
428
+ try {
429
+ const controller = createTestInputor({ value: "start" })
430
+ let inputCalls = 0
431
+ let valueCalls = 0
432
+ let schemaCalls = 0
433
+
434
+ await controller.waitForReady()
435
+ controller.subscribeInputChange(() => {
436
+ inputCalls = inputCalls + 1
437
+ })
438
+ controller.subscribeValueChange(() => {
439
+ valueCalls = valueCalls + 1
440
+ })
441
+ controller.subscribeSchemaChange(() => {
442
+ schemaCalls = schemaCalls + 1
443
+ })
444
+ controller.destroy()
445
+
446
+ await controller.updateInputValue("next")
447
+ await vi.advanceTimersByTimeAsync(0)
448
+ await controller.updateValue("final")
449
+ await controller.updatePlaceholder("after-destroy")
450
+
451
+ expect(inputCalls).toBe(0)
452
+ expect(valueCalls).toBe(0)
453
+ expect(schemaCalls).toBe(0)
454
+ }
455
+ finally {
456
+ vi.useRealTimers()
457
+ }
458
+ })
@@ -0,0 +1,30 @@
1
+ import { expect, test } from "vitest"
2
+
3
+ import {
4
+ BOOLEAN_INPUTOR_TYPE_NAME,
5
+ BooleanInputorController,
6
+ } from "#Source/form/index.ts"
7
+
8
+ test("BooleanInputorController.getSchema exposes boolean schema state and updateValue toggles it", async () => {
9
+ const controller = new BooleanInputorController({
10
+ id: "boolean-id",
11
+ value: false,
12
+ })
13
+
14
+ await controller.waitForReady()
15
+ await controller.updateValue(true)
16
+
17
+ expect(await controller.getSchema()).toEqual({
18
+ inputorTypeName: BOOLEAN_INPUTOR_TYPE_NAME,
19
+ id: "boolean-id",
20
+ name: `boolean-boolean-id`,
21
+ placeholder: "",
22
+ value: true,
23
+ isVoid: false,
24
+ isFocused: false,
25
+ isTouched: false,
26
+ isDirty: true,
27
+ isDisabled: false,
28
+ isDebugMode: false,
29
+ })
30
+ })
@@ -0,0 +1,27 @@
1
+ import { expect, test } from "vitest"
2
+
3
+ import {
4
+ FILE_INPUTOR_TYPE_NAME,
5
+ FileInputorController,
6
+ } from "#Source/form/index.ts"
7
+
8
+ test("FileInputorController.getSchema stores file values and reports file metadata", async () => {
9
+ const file = new File(["alpha"], "alpha.txt", {
10
+ type: "text/plain",
11
+ })
12
+ const controller = new FileInputorController({
13
+ id: "file-id",
14
+ value: file,
15
+ })
16
+
17
+ await controller.waitForReady()
18
+
19
+ const schema = await controller.getSchema()
20
+
21
+ expect(schema.inputorTypeName).toBe(FILE_INPUTOR_TYPE_NAME)
22
+ expect(schema.id).toBe("file-id")
23
+ expect(schema.name).toBe("file-file-id")
24
+ expect(schema.value?.name).toBe("alpha.txt")
25
+ expect(schema.value?.type).toBe("text/plain")
26
+ expect(schema.isDirty).toBe(false)
27
+ })
@@ -0,0 +1,120 @@
1
+ import { expect, test } from "vitest"
2
+
3
+ import {
4
+ FormInputorController,
5
+ NumberInputorController,
6
+ TextInputorController,
7
+ } from "#Source/form/index.ts"
8
+
9
+ const createItems = (): {
10
+ name: TextInputorController
11
+ age: NumberInputorController
12
+ } => {
13
+ return {
14
+ name: new TextInputorController({
15
+ id: "form-name-id",
16
+ value: "alpha",
17
+ }),
18
+ age: new NumberInputorController({
19
+ id: "form-age-id",
20
+ value: 1,
21
+ min: 0,
22
+ max: 99,
23
+ }),
24
+ }
25
+ }
26
+
27
+ test("FormInputorController.updateValue decodes external values into child items", async () => {
28
+ const items = createItems()
29
+ const controller = new FormInputorController<
30
+ { name: string | undefined; age: number | undefined },
31
+ typeof items
32
+ >({
33
+ id: "form-id",
34
+ value: {
35
+ name: "alpha",
36
+ age: 1,
37
+ },
38
+ items,
39
+ encodeValue: (schemaDict) => {
40
+ return {
41
+ name: schemaDict.name.value,
42
+ age: schemaDict.age.value,
43
+ }
44
+ },
45
+ decodeValue: (value) => {
46
+ return {
47
+ name: value.name,
48
+ age: value.age,
49
+ }
50
+ },
51
+ })
52
+
53
+ await Promise.all([
54
+ items.name.waitForReady(),
55
+ items.age.waitForReady(),
56
+ controller.waitForReady(),
57
+ ])
58
+ await controller.updateValue({
59
+ name: "beta",
60
+ age: 8,
61
+ })
62
+
63
+ expect((await items.name.getSchema()).value).toBe("beta")
64
+ expect((await items.age.getSchema()).value).toBe(8)
65
+ expect((await controller.getSchema()).value).toEqual({
66
+ name: "beta",
67
+ age: 8,
68
+ })
69
+ })
70
+
71
+ test("FormInputorController reacts to child schema changes through encodeValue", async () => {
72
+ const items = createItems()
73
+ const controller = new FormInputorController<
74
+ { name: string | undefined; age: number | undefined },
75
+ typeof items
76
+ >({
77
+ id: "form-id",
78
+ value: {
79
+ name: "alpha",
80
+ age: 1,
81
+ },
82
+ items,
83
+ encodeValue: (schemaDict) => {
84
+ return {
85
+ name: schemaDict.name.value,
86
+ age: schemaDict.age.value,
87
+ }
88
+ },
89
+ decodeValue: (value) => {
90
+ return {
91
+ name: value.name,
92
+ age: value.age,
93
+ }
94
+ },
95
+ })
96
+
97
+ await Promise.all([
98
+ items.name.waitForReady(),
99
+ items.age.waitForReady(),
100
+ controller.waitForReady(),
101
+ ])
102
+ await Promise.resolve()
103
+
104
+ const nextFormValue = new Promise<{ name: string | undefined; age: number | undefined }>((resolve) => {
105
+ controller.subscribeValueChange((context) => {
106
+ resolve(context.newValue)
107
+ })
108
+ })
109
+
110
+ await items.name.updateValue("gamma")
111
+
112
+ expect(await nextFormValue).toEqual({
113
+ name: "gamma",
114
+ age: 1,
115
+ })
116
+ expect((await controller.getSchema()).value).toEqual({
117
+ name: "gamma",
118
+ age: 1,
119
+ })
120
+ })
@@ -0,0 +1,67 @@
1
+ import { expect, test } from "vitest"
2
+
3
+ import {
4
+ BooleanInputorController,
5
+ FileInputorController,
6
+ FormInputorController,
7
+ MultiSelectInputorController,
8
+ NumberInputorController,
9
+ SelectInputorController,
10
+ TextInputorController,
11
+ boolean as createBooleanInputor,
12
+ file as createFileInputor,
13
+ form as createFormInputor,
14
+ multiSelect as createMultiSelectInputor,
15
+ number as createNumberInputor,
16
+ select as createSelectInputor,
17
+ text as createTextInputor,
18
+ } from "#Source/form/index.ts"
19
+
20
+ test("boolean creates a BooleanInputorController", () => {
21
+ expect(createBooleanInputor({ value: false })).toBeInstanceOf(BooleanInputorController)
22
+ })
23
+
24
+ test("number creates a NumberInputorController", () => {
25
+ expect(createNumberInputor({ value: 1 })).toBeInstanceOf(NumberInputorController)
26
+ })
27
+
28
+ test("text creates a TextInputorController", () => {
29
+ expect(createTextInputor({ value: "alpha" })).toBeInstanceOf(TextInputorController)
30
+ })
31
+
32
+ test("file creates a FileInputorController", () => {
33
+ expect(createFileInputor({ value: undefined })).toBeInstanceOf(FileInputorController)
34
+ })
35
+
36
+ test("select creates a SelectInputorController", () => {
37
+ expect(createSelectInputor({ value: [] })).toBeInstanceOf(SelectInputorController)
38
+ })
39
+
40
+ test("multiSelect creates a MultiSelectInputorController", () => {
41
+ expect(createMultiSelectInputor({ value: [] })).toBeInstanceOf(MultiSelectInputorController)
42
+ })
43
+
44
+ test("form creates a FormInputorController", () => {
45
+ const nameController = createTextInputor({ value: "alpha" })
46
+ const ageController = createNumberInputor({ value: 1 })
47
+
48
+ expect(createFormInputor({
49
+ value: {
50
+ name: "alpha",
51
+ age: 1,
52
+ },
53
+ items: {
54
+ name: nameController,
55
+ age: ageController,
56
+ },
57
+ encodeValue: (schemaDict) => {
58
+ return {
59
+ name: schemaDict.name.value,
60
+ age: schemaDict.age.value,
61
+ }
62
+ },
63
+ decodeValue: (value) => {
64
+ return value
65
+ },
66
+ })).toBeInstanceOf(FormInputorController)
67
+ })