@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,105 @@
1
+ # Route
2
+
3
+ ## Description
4
+
5
+ Route 模块提供围绕命中入口表达、地址片段归一化、路由历史推进以及宿主桥接的基础建模能力。
6
+
7
+ 它关注的不是某个框架路由器的页面约定,也不是对浏览器 `location`、`history` 或某个导航 API 的临时封装,而是“一个系统中的当前位置或目标入口,如何被表达为稳定、可比较、可派生、可推进的公共语义”这一更一般的问题。浏览器 URL 是 route 的典型形态,但不是唯一形态。只要某个系统里存在“某个输入命中某个稳定入口,并伴随一组可解释片段或参数”的过程,就存在 route 语义。因此,这个模块更适合被理解为路由领域的基础模型集合,而不是浏览器导航工具箱、前端框架路由方案或零散的 URL 处理函数集合。
8
+
9
+ ## For Understanding
10
+
11
+ 理解 Route 模块时,应优先把它看作“当前命中入口及其变化过程”的建模层,而不是把它缩窄成页面跳转工具。这个模块当前表达的核心问题有三层:一是地址片段如何被归一化为稳定表示;二是当前路由如何作为一个可读取、可比较、可派生的对象存在;三是路由历史如何被推进、替换、漫游、回退,并以清楚语义向上层暴露。
12
+
13
+ 这里的 route 不必被限制在浏览器页面地址中。更一般地说,只要某个系统存在“命中入口”的过程,就可以出现 route 语义。例如浏览器应用中的页面或视图入口、服务端系统中的路径分发入口、CLI 中的命令入口,以及任务系统中的某个目标节点入口,本质上都在回答“输入如何命中某个稳定目标,以及这个目标如何和片段、参数、历史一起被组织起来”这一问题。Route 模块关心的是这个抽象层,而不是某一种宿主上的具体表现。
14
+
15
+ 从当前目录结构看,这个模块由三个子边界构成:
16
+
17
+ - `uri`:负责 `pathname`、`search`、`hash` 等片段的归一化、转换与比较语义。
18
+ - `router`:负责 `Route`、`Router`、历史记录以及各类导航动作的模型化表达。
19
+ - `adapter`:负责把 Route 模型接到具体宿主上,例如浏览器环境或响应式消费面。
20
+
21
+ 理解这个模块时,还应守住几条边界:
22
+
23
+ - Route 模块表达的是“入口及其历史”的基础模型,不负责替代页面渲染系统、框架路由约定、服务端业务编排、CLI 参数解析器或权限体系。
24
+ - 它可以和浏览器、服务端、CLI 或响应式系统对接,但不应让某个宿主的临时 API 细节反过来定义模块公共语义。
25
+ - 它适合承载入口片段、标准化路由记录、历史动作以及宿主同步边界,但不应直接承担组件装载、数据预取、业务参数解释、命令执行副作用或框架专属生命周期。
26
+ - `adapter` 更适合作为桥接层理解。它的职责是把既有 Route 模型接入宿主,而不是把宿主细节直接提升为父模块语义。
27
+
28
+ ## For Using
29
+
30
+ 当你希望在应用或库中复用一套不依赖具体页面结构、能够稳定表达“当前命中入口”和“入口历史”的基础能力时,可以使用 Route 模块。
31
+
32
+ 从使用角度看,这个模块大致可以分为三类能力:
33
+
34
+ - 地址片段能力:把 `pathname`、`search`、`hash` 等结构收束成稳定表示,并支持统一的转换、包含与比较语义。
35
+ - 路由模型能力:把当前地址、标准化记录、历史链路以及导航动作组织为一套清楚的对象模型。
36
+ - 宿主桥接能力:把内部 Router 与浏览器历史或响应式消费面连接起来,使上层系统能够围绕统一的 Route 语义工作。
37
+
38
+ 更合适的接入方式,通常是先判断你的问题是否真的属于 route 边界。如果你需要的是:
39
+
40
+ - 让地址片段形成稳定且可比较的统一表示;
41
+ - 把当前地址收束到一个可复用的路由对象和标准化记录中;
42
+ - 明确区分 navigate、redirect、replace、go、roaming 等历史动作的语义;
43
+ - 将内部 Router 同浏览器历史或响应式消费面连接起来;
44
+
45
+ 那么这个模块就是合适的边界。
46
+
47
+ 相反,如果你的需求主要是页面组件树装载、业务参数校验、访问权限决策、SEO 约定、框架页面生命周期、命令执行副作用或服务端领域逻辑分派,那么这些通常不应直接成为 Route 模块本身的职责,而应放在更外层系统或具体框架集成层中。
48
+
49
+ ## For Contributing
50
+
51
+ 为 Route 模块贡献内容时,优先判断新增能力是否真的在澄清“入口如何表达、如何标准化、如何形成历史、如何与宿主同步”这一稳定问题域,而不是只是在给某个当前宿主补一层便捷封装。这个模块应长期服务于入口片段、路由对象、历史语义与桥接边界这几个方向,而不是退化成浏览器导航工具目录或某个框架的外围辅助层。
52
+
53
+ 扩展时应特别警惕两类偏差。一类是把 `uri` 层做成只对某组业务参数、某条服务路径或某套 CLI 选项成立的临时工具,导致公共语义不稳定;另一类是让 `adapter` 下沉过多桥接之外的职责,例如页面装载、业务状态解释、命令执行、副作用编排或框架专属生命周期。更稳妥的做法,是先确认新增能力究竟属于片段语义、路由历史语义,还是宿主桥接语义,再把它放到对应子边界中。
54
+
55
+ 当前 `adapter` 下的能力更适合被理解为桥接层,因此不要求为其编写单元测试。这并不是说这些代码永远不可测试,而是因为它们主要依赖浏览器事件或响应式系统等宿主前提;在当前模块边界下,优先保证 `uri` 与 `router` 这些环境中立、语义稳定的核心部分被充分测试,通常比为桥接细节重复编写单元测试更有价值。如果未来某个适配器逐渐沉淀出脱离宿主也成立的稳定公共语义,再考虑为其引入单元测试。
56
+
57
+ ### JSDoc 注释格式要求
58
+
59
+ - 每个公开导出的目标(类型、函数、变量、类等)都应包含 JSDoc 注释,让人在不跳转实现的情况下就能理解用途。
60
+ - JSDoc 注释第一行应为清晰且简洁的描述,该描述优先使用中文(英文也可以)。
61
+ - 如果描述后还有其他内容,应在描述后加一个空行。
62
+ - 如果有示例,应使用 `@example` 标签,后接三重反引号代码块(不带语言标识)。
63
+ - 如果有示例,应包含多个场景,展示不同用法,尤其要覆盖常见组合方式或边界输入。
64
+ - 如果有示例,应使用注释格式说明每个场景:`// Expect: <result>`。
65
+ - 如果有示例,应将结果赋值给 `example1`、`example2` 之类的变量,以保持示例易读。
66
+ - 如果有示例,`// Expect: <result>` 应该位于 `example1`、`example2` 之前,以保持示例的逻辑清晰。
67
+ - 如果有示例,应优先使用确定性示例;避免断言精确的随机输出。
68
+ - 如果函数返回结构化字符串,应展示其预期格式特征。
69
+ - 如果有参考资料,应将 `@see` 放在 `@example` 代码块之后,并用一个空行分隔。
70
+
71
+ ### 实现规范要求
72
+
73
+ - 不同程序元素之间使用一个空行分隔,保持结构清楚。这里的程序元素,通常指函数、类型、常量,以及直接服务于它们的辅助元素。
74
+ - 某程序元素独占的辅助元素与该程序元素本身视为一个整体,不要在它们之间添加空行。
75
+ - 程序元素的辅助元素应该放置在该程序元素的上方,以保持阅读时的逻辑顺序。
76
+ - 若辅助元素被多个程序元素共享,则应将其视为独立的程序元素,放在这些程序元素中第一个相关目标的上方,并与后续程序元素之间保留一个空行。
77
+ - 辅助元素也应该像其它程序元素一样,保持清晰的命名和适当的注释,以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
78
+ - 辅助元素的命名必须以前缀 `internal` 开头(或 `Internal`,大小写不敏感)。
79
+ - 辅助元素永远不要公开导出。
80
+ - 被模块内多个不同文件中的程序元素共享的辅助元素,应该放在一个单独的文件中,例如 `./src/route/internal.ts`。
81
+ - 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时,才应将其视为子模块。
82
+ - 子模块包含多个文件时,应该为其单独创建子文件夹,并为其创建单独的 Barrel 文件;父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
83
+ - 子模块不需要有自己的 `README.md`。
84
+ - 子模块可以有自己的 `internal.ts` 文件,多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中,单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
85
+ - 对模块依赖关系的要求(通常是不循环依赖或不反向依赖)与对 DRY 的要求可能产生冲突。此时,若复用的代码数量不大,可以适当牺牲 DRY,复制粘贴并保留必要的注释说明;若复用的代码数量较大,则可以将其抽象到新的文件或子模块中,如 `common.ts`,并在需要的地方导入使用。
86
+ - 与 route 相关的实现应优先围绕入口片段语义、路由对象、历史推进动作和宿主桥接边界组织,避免把页面装载、服务端业务处理、CLI 命令执行、业务专属参数解释或框架专属生命周期直接提升为 Route 的长期公共语义。
87
+
88
+ ### 导出策略要求
89
+
90
+ - 保持内部辅助项和内部符号为私有,不要让外部接入依赖临时性的内部结构。
91
+ - 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
92
+ - Barrel 文件应命名为 `index.ts`,放在模块目录根部,并且所有公共 API 都应从该文件导出。
93
+ - 新增公共能力时,应优先检查它是否表达稳定、清楚且值得长期维护的路由语义,而不是某段浏览器实现细节、宿主桥接细节或业务约定的便捷暴露;仅在确认需要长期对外承诺时再加入 Barrel 导出。
94
+
95
+ ### 测试要求
96
+
97
+ - 若程序元素是函数,则只为该函数编写一个测试,如果该函数需要测试多个用例,应放在同一个测试中。
98
+ - 若程序元素是类,则至少要为该类的每一个方法编写一个测试,如果该方法需要测试多个用例,应放在同一个测试中。
99
+ - 若程序元素是类,除了为该类的每一个方法编写至少一个测试之外,还可以为该类编写任意多个测试,以覆盖该类的不同使用场景或边界情况。
100
+ - 若编写测试时需要用到辅助元素(Mock 或 Spy 等),可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单,则可以直接放在每一个测试内部,优先保证每个测试的独立性,而不是追求极致 DRY;若辅助元素较为复杂或需要在多个测试中复用,则可以放在测试文件顶部,供该测试文件中的所有测试使用。
101
+ - 测试顺序应与源文件中被测试目标的原始顺序保持一致。
102
+ - 若该模块不需要测试,必须在说明文件中明确说明该模块不需要测试,并说明理由。一般来说,只有在该模块没有可执行的公共函数、只承载类型层表达,或其语义已被上层模块的测试完整覆盖且重复测试几乎不再带来额外价值时,才适合这样处理。
103
+ - 模块的单元测试文件目录是 `./tests/unit/route`,若模块包含子模块,则子模块的单元测试文件目录为 `./tests/unit/route/<sub-module-name>`。
104
+ - `adapter` 目录当前无需编写单元测试,并应在模块文档中明确说明这是因为它主要承担宿主桥接职责,核心语义应优先由 `uri` 与 `router` 层测试覆盖。
105
+ - 对这个模块来说,测试应优先覆盖入口片段归一化、Route 标准化记录、Router 的历史推进与替换语义、回退与漫游边界,以及关键动作产生的历史记录与事件行为。
@@ -0,0 +1,122 @@
1
+ import { createRoute } from "../router/index.ts"
2
+ import type { Route, Router } from "../router/index.ts"
3
+
4
+ /**
5
+ * 创建浏览器路由适配器时需要的输入项。
6
+ */
7
+ export interface CreateBrowserRouterOptions {
8
+ router: Router
9
+ }
10
+
11
+ /**
12
+ * 浏览器路由适配器返回的结果。
13
+ *
14
+ * `dispose` 用于释放当前适配器注册的订阅和浏览器事件监听器。
15
+ */
16
+ export interface CreateBrowserRouterResult {
17
+ router: Router
18
+ dispose: () => void
19
+ }
20
+
21
+ /**
22
+ * 将 Router 和浏览器路由对接在一起,将 Router 作为唯一信源。
23
+ *
24
+ * 该适配器负责把 Router 产生的历史记录同步到浏览器 `history`,并在浏览器
25
+ * `popstate` 或 `hashchange` 发生时,把新的地址变化回灌到 Router。
26
+ *
27
+ * Tips:
28
+ * - 浏览器 F5 刷新之后 `history.state` 不会丢失。
29
+ */
30
+ export const createBrowserRouter = (options: CreateBrowserRouterOptions): CreateBrowserRouterResult => {
31
+ const { router } = options
32
+
33
+ interface State {
34
+ routeHistoryEntryId: string
35
+ }
36
+ const isState = (target: unknown): target is State => {
37
+ if (typeof target !== "object" || target === null) {
38
+ return false
39
+ }
40
+ if (("routeHistoryEntryId" in target) === false) {
41
+ return false
42
+ }
43
+ if (typeof target["routeHistoryEntryId"] !== "string") {
44
+ return false
45
+ }
46
+ return true
47
+ }
48
+ const insertState = (route: Route, state: State): void => {
49
+ const url = location.origin + route.getRecord().partialUrl
50
+ window.history.pushState(state, "", url)
51
+ }
52
+ const updateState = (route: Route, state: State): void => {
53
+ const url = location.origin + route.getRecord().partialUrl
54
+ window.history.replaceState(state, "", url)
55
+ }
56
+ const upsertState = (route: Route, state: State): void => {
57
+ const oldUrl = location.origin + createRoute(location.href).getRecord().partialUrl
58
+ const newUrl = location.origin + route.getRecord().partialUrl
59
+ if (oldUrl === newUrl) {
60
+ updateState(route, state)
61
+ } else {
62
+ insertState(route, state)
63
+ }
64
+ }
65
+
66
+ const subscriberEntry = router.eventManager.subscribe("history", (routeHistoryEntry) => {
67
+ upsertState(routeHistoryEntry.to.route, { routeHistoryEntryId: routeHistoryEntry.id })
68
+ })
69
+ const disposeRouterSubscriber = (): void => {
70
+ subscriberEntry.unsubscribe()
71
+ }
72
+
73
+ const popstateEventListener = (event: PopStateEvent): void => {
74
+ // 此事件触发的结果有两种:
75
+ // 1. 来到 Router 设置的路由,此时 state 可识别。
76
+ // 2. 来到非 Router 设置的路由,此时 state 不可识别。
77
+ //
78
+ // 对于 1,判断 state 中的 routeHistoryEntryId 是否与 router 的
79
+ // 最新的 routeHistoryEntry 的 id 相同,若相同,则说明此事件由 router
80
+ // 触发,不需要再次操作(否则会导致循环触发),若不同,则作为新路由同步至
81
+ // router。
82
+ // 对于 2,始终作为新路由同步至 router。
83
+
84
+ if (isState(event.state)) {
85
+ const currentRouteHistoryEntryId = router.getCurrentRouteHistoryEntryId()
86
+ if (event.state.routeHistoryEntryId === currentRouteHistoryEntryId) {
87
+ return
88
+ }
89
+ }
90
+
91
+ router.navigateTo({ url: location.href })
92
+ }
93
+ window.addEventListener("popstate", popstateEventListener)
94
+ const disposePopstateEventListener = (): void => {
95
+ window.removeEventListener("popstate", popstateEventListener)
96
+ }
97
+
98
+ const hashchangeEventListener = (event: HashChangeEvent): void => {
99
+ if (isState(history.state)) {
100
+ const currentRouteHistoryEntryId = router.getCurrentRouteHistoryEntryId()
101
+ if (history.state.routeHistoryEntryId === currentRouteHistoryEntryId) {
102
+ return
103
+ }
104
+ }
105
+ router.navigateTo({ url: event.newURL })
106
+ }
107
+ window.addEventListener("hashchange", hashchangeEventListener)
108
+ const disposeHashchangeEventListener = (): void => {
109
+ window.removeEventListener("hashchange", hashchangeEventListener)
110
+ }
111
+
112
+ const dispose = (): void => {
113
+ disposeRouterSubscriber()
114
+ disposePopstateEventListener()
115
+ disposeHashchangeEventListener()
116
+ }
117
+
118
+ return {
119
+ router,
120
+ dispose
121
+ }
122
+ }
@@ -0,0 +1,56 @@
1
+ import type { Computed } from "#Source/reactor/index.ts"
2
+ import { computed, signal } from "#Source/reactor/index.ts"
3
+ import type { Route, RouteHistoryEntry, Router, RouteRecord } from "../router/index.ts"
4
+
5
+ /**
6
+ * 创建路由驱动器时需要的输入项。
7
+ */
8
+ export interface CreateRouteDriverOptions {
9
+ router: Router
10
+ }
11
+
12
+ /**
13
+ * 将 Router 暴露为响应式只读视图的驱动器。
14
+ *
15
+ * 该接口把当前历史记录、当前 Route 以及当前 RouteRecord 暴露为可追踪的计算值,
16
+ * 方便响应式系统消费。
17
+ */
18
+ export interface RouteDriver {
19
+ router: Router
20
+ routeHistoryEntry: Computed<RouteHistoryEntry>
21
+ route: Computed<Route>
22
+ routeRecord: Computed<RouteRecord>
23
+ }
24
+
25
+ /**
26
+ * 基于 Router 创建一组可响应追踪的当前路由派生值。
27
+ *
28
+ * 返回结果中的计算值会随着 Router 的 `history` 事件自动更新。
29
+ */
30
+ export const createRouteDriver = (options: CreateRouteDriverOptions): RouteDriver => {
31
+ const { router } = options
32
+
33
+ const internalCurrentRouteHistoryEntry = signal(() => {
34
+ return router.getCurrentRouteHistoryEntry()
35
+ })
36
+ router.eventManager.subscribe("history", (routeHistoryEntry) => {
37
+ internalCurrentRouteHistoryEntry.set(routeHistoryEntry)
38
+ })
39
+
40
+ const currentRouteHistoryEntry = computed(() => {
41
+ return internalCurrentRouteHistoryEntry.get()
42
+ })
43
+ const currentRoute = computed(() => {
44
+ return currentRouteHistoryEntry.get().to.route
45
+ })
46
+ const currentRouteRecord = computed(() => {
47
+ return currentRoute.get().getRecord()
48
+ })
49
+
50
+ return {
51
+ router,
52
+ routeHistoryEntry: currentRouteHistoryEntry,
53
+ route: currentRoute,
54
+ routeRecord: currentRouteRecord
55
+ }
56
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./driver.ts"
2
+ export * from "./browser.ts"
@@ -0,0 +1,3 @@
1
+ export * from "./uri/index.ts"
2
+ export * from "./router/index.ts"
3
+ export * from "./adapter/index.ts"
@@ -0,0 +1,2 @@
1
+ export * from "./route.ts"
2
+ export * from "./router.ts"