@lakutata/entrypoint 3.0.0-beta.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 (325) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +183 -0
  3. package/THIRD_PARTY_NOTICES.md +206 -0
  4. package/dist/cjs/Entrypoint.d.ts +868 -0
  5. package/dist/cjs/Entrypoint.js +998 -0
  6. package/dist/cjs/adapter/commander/CommanderCLIEntrypoint.d.ts +192 -0
  7. package/dist/cjs/adapter/commander/CommanderCLIEntrypoint.js +439 -0
  8. package/dist/cjs/adapter/commander/Prompt.d.ts +22 -0
  9. package/dist/cjs/adapter/commander/Prompt.js +164 -0
  10. package/dist/cjs/adapter/commander/Width.d.ts +12 -0
  11. package/dist/cjs/adapter/commander/Width.js +67 -0
  12. package/dist/cjs/adapter/electron/ElectronIPCServiceEntrypoint.d.ts +203 -0
  13. package/dist/cjs/adapter/electron/ElectronIPCServiceEntrypoint.js +249 -0
  14. package/dist/cjs/adapter/express/ExpressHTTPEntrypoint.d.ts +172 -0
  15. package/dist/cjs/adapter/express/ExpressHTTPEntrypoint.js +301 -0
  16. package/dist/cjs/adapter/express/Responders.d.ts +89 -0
  17. package/dist/cjs/adapter/express/Responders.js +71 -0
  18. package/dist/cjs/adapter/express/StaticUI.d.ts +83 -0
  19. package/dist/cjs/adapter/express/StaticUI.js +104 -0
  20. package/dist/cjs/adapter/fastify/FastifyHTTPEntrypoint.d.ts +156 -0
  21. package/dist/cjs/adapter/fastify/FastifyHTTPEntrypoint.js +339 -0
  22. package/dist/cjs/adapter/fastify/Responders.d.ts +88 -0
  23. package/dist/cjs/adapter/fastify/Responders.js +77 -0
  24. package/dist/cjs/adapter/http/HTTPServiceEntrypoint.d.ts +117 -0
  25. package/dist/cjs/adapter/http/HTTPServiceEntrypoint.js +257 -0
  26. package/dist/cjs/adapter/jsonrpc/JSONRPCProtocol.d.ts +194 -0
  27. package/dist/cjs/adapter/jsonrpc/JSONRPCProtocol.js +187 -0
  28. package/dist/cjs/adapter/jsonrpc/JSONRPCServiceEntrypoint.d.ts +154 -0
  29. package/dist/cjs/adapter/jsonrpc/JSONRPCServiceEntrypoint.js +397 -0
  30. package/dist/cjs/adapter/schedule/ScheduleEntrypoint.d.ts +86 -0
  31. package/dist/cjs/adapter/schedule/ScheduleEntrypoint.js +275 -0
  32. package/dist/cjs/adapter/socket.io/SocketIOServiceEntrypoint.d.ts +138 -0
  33. package/dist/cjs/adapter/socket.io/SocketIOServiceEntrypoint.js +216 -0
  34. package/dist/cjs/channel/BuiltinChannels.d.ts +18 -0
  35. package/dist/cjs/channel/BuiltinChannels.js +128 -0
  36. package/dist/cjs/channel/Channel.d.ts +196 -0
  37. package/dist/cjs/channel/Channel.js +106 -0
  38. package/dist/cjs/channel/EntrypointAdapter.d.ts +195 -0
  39. package/dist/cjs/channel/EntrypointAdapter.js +43 -0
  40. package/dist/cjs/context/BaseContext.d.ts +75 -0
  41. package/dist/cjs/context/BaseContext.js +90 -0
  42. package/dist/cjs/context/CLIContext.d.ts +38 -0
  43. package/dist/cjs/context/CLIContext.js +53 -0
  44. package/dist/cjs/context/HTTPContext.d.ts +52 -0
  45. package/dist/cjs/context/HTTPContext.js +78 -0
  46. package/dist/cjs/context/ScheduleContext.d.ts +47 -0
  47. package/dist/cjs/context/ScheduleContext.js +65 -0
  48. package/dist/cjs/context/ServiceContext.d.ts +47 -0
  49. package/dist/cjs/context/ServiceContext.js +62 -0
  50. package/dist/cjs/decorators/CLIAction.d.ts +120 -0
  51. package/dist/cjs/decorators/CLIAction.js +13 -0
  52. package/dist/cjs/decorators/HTTPAction.d.ts +178 -0
  53. package/dist/cjs/decorators/HTTPAction.js +14 -0
  54. package/dist/cjs/decorators/Prefix.d.ts +44 -0
  55. package/dist/cjs/decorators/Prefix.js +48 -0
  56. package/dist/cjs/decorators/Schedule.d.ts +120 -0
  57. package/dist/cjs/decorators/Schedule.js +64 -0
  58. package/dist/cjs/decorators/ServiceAction.d.ts +116 -0
  59. package/dist/cjs/decorators/ServiceAction.js +12 -0
  60. package/dist/cjs/decorators/UseMiddlewares.d.ts +52 -0
  61. package/dist/cjs/decorators/UseMiddlewares.js +58 -0
  62. package/dist/cjs/decorators/http/DELETE.d.ts +87 -0
  63. package/dist/cjs/decorators/http/DELETE.js +7 -0
  64. package/dist/cjs/decorators/http/GET.d.ts +89 -0
  65. package/dist/cjs/decorators/http/GET.js +7 -0
  66. package/dist/cjs/decorators/http/HEAD.d.ts +84 -0
  67. package/dist/cjs/decorators/http/HEAD.js +7 -0
  68. package/dist/cjs/decorators/http/OPTIONS.d.ts +80 -0
  69. package/dist/cjs/decorators/http/OPTIONS.js +7 -0
  70. package/dist/cjs/decorators/http/PATCH.d.ts +90 -0
  71. package/dist/cjs/decorators/http/PATCH.js +7 -0
  72. package/dist/cjs/decorators/http/POST.d.ts +91 -0
  73. package/dist/cjs/decorators/http/POST.js +7 -0
  74. package/dist/cjs/decorators/http/PUT.d.ts +92 -0
  75. package/dist/cjs/decorators/http/PUT.js +7 -0
  76. package/dist/cjs/exceptions/AccessDeniedException.d.ts +10 -0
  77. package/dist/cjs/exceptions/AccessDeniedException.js +17 -0
  78. package/dist/cjs/exceptions/ControllerActionNotFoundException.d.ts +9 -0
  79. package/dist/cjs/exceptions/ControllerActionNotFoundException.js +16 -0
  80. package/dist/cjs/exceptions/DuplicateActionNameException.d.ts +8 -0
  81. package/dist/cjs/exceptions/DuplicateActionNameException.js +15 -0
  82. package/dist/cjs/exceptions/EntrypointStoppedException.d.ts +9 -0
  83. package/dist/cjs/exceptions/EntrypointStoppedException.js +16 -0
  84. package/dist/cjs/exceptions/InvalidActionGroupException.d.ts +4 -0
  85. package/dist/cjs/exceptions/InvalidActionGroupException.js +11 -0
  86. package/dist/cjs/exceptions/InvalidChannelException.d.ts +8 -0
  87. package/dist/cjs/exceptions/InvalidChannelException.js +15 -0
  88. package/dist/cjs/exceptions/InvalidEntrypointAdapterException.d.ts +9 -0
  89. package/dist/cjs/exceptions/InvalidEntrypointAdapterException.js +16 -0
  90. package/dist/cjs/exceptions/InvalidMiddlewareException.d.ts +8 -0
  91. package/dist/cjs/exceptions/InvalidMiddlewareException.js +15 -0
  92. package/dist/cjs/exceptions/InvalidPrefixException.d.ts +8 -0
  93. package/dist/cjs/exceptions/InvalidPrefixException.js +15 -0
  94. package/dist/cjs/exceptions/MiddlewareNextCalledException.d.ts +8 -0
  95. package/dist/cjs/exceptions/MiddlewareNextCalledException.js +15 -0
  96. package/dist/cjs/exceptions/RouteNotFoundException.d.ts +9 -0
  97. package/dist/cjs/exceptions/RouteNotFoundException.js +16 -0
  98. package/dist/cjs/exceptions/ServiceInvokeException.d.ts +11 -0
  99. package/dist/cjs/exceptions/ServiceInvokeException.js +14 -0
  100. package/dist/cjs/exports/CTRLDecorators.d.ts +13 -0
  101. package/dist/cjs/exports/CTRLDecorators.js +38 -0
  102. package/dist/cjs/exports/Channel.d.ts +14 -0
  103. package/dist/cjs/exports/Channel.js +33 -0
  104. package/dist/cjs/exports/CommanderAdapter.d.ts +1 -0
  105. package/dist/cjs/exports/CommanderAdapter.js +8 -0
  106. package/dist/cjs/exports/ElectronAdapter.d.ts +1 -0
  107. package/dist/cjs/exports/ElectronAdapter.js +9 -0
  108. package/dist/cjs/exports/Entrypoint.d.ts +24 -0
  109. package/dist/cjs/exports/Entrypoint.js +55 -0
  110. package/dist/cjs/exports/ExpressAdapter.d.ts +4 -0
  111. package/dist/cjs/exports/ExpressAdapter.js +15 -0
  112. package/dist/cjs/exports/FastifyAdapter.d.ts +4 -0
  113. package/dist/cjs/exports/FastifyAdapter.js +14 -0
  114. package/dist/cjs/exports/JSONRPCAdapter.d.ts +2 -0
  115. package/dist/cjs/exports/JSONRPCAdapter.js +11 -0
  116. package/dist/cjs/exports/SocketIOAdapter.d.ts +1 -0
  117. package/dist/cjs/exports/SocketIOAdapter.js +9 -0
  118. package/dist/cjs/lib/AccessControl.d.ts +118 -0
  119. package/dist/cjs/lib/AccessControl.js +208 -0
  120. package/dist/cjs/lib/AccessControlRule.d.ts +91 -0
  121. package/dist/cjs/lib/AccessControlRule.js +76 -0
  122. package/dist/cjs/lib/ActionOptions.d.ts +67 -0
  123. package/dist/cjs/lib/ActionOptions.js +67 -0
  124. package/dist/cjs/lib/ActionResult.d.ts +28 -0
  125. package/dist/cjs/lib/ActionResult.js +28 -0
  126. package/dist/cjs/lib/ApplicationOf.d.ts +6 -0
  127. package/dist/cjs/lib/ApplicationOf.js +14 -0
  128. package/dist/cjs/lib/Controller.d.ts +59 -0
  129. package/dist/cjs/lib/Controller.js +64 -0
  130. package/dist/cjs/lib/ControllerEntrypoint.d.ts +168 -0
  131. package/dist/cjs/lib/ControllerEntrypoint.js +239 -0
  132. package/dist/cjs/lib/GetActionDTOAndOptions.d.ts +29 -0
  133. package/dist/cjs/lib/GetActionDTOAndOptions.js +49 -0
  134. package/dist/cjs/lib/HTTPErrors.d.ts +55 -0
  135. package/dist/cjs/lib/HTTPErrors.js +52 -0
  136. package/dist/cjs/lib/Middleware.d.ts +146 -0
  137. package/dist/cjs/lib/Middleware.js +144 -0
  138. package/dist/cjs/lib/Prefix.d.ts +98 -0
  139. package/dist/cjs/lib/Prefix.js +151 -0
  140. package/dist/cjs/lib/Result.d.ts +173 -0
  141. package/dist/cjs/lib/Result.js +153 -0
  142. package/dist/cjs/lib/ServiceResponseCodec.d.ts +82 -0
  143. package/dist/cjs/lib/ServiceResponseCodec.js +117 -0
  144. package/dist/cjs/lib/StringifyPattern.d.ts +7 -0
  145. package/dist/cjs/lib/StringifyPattern.js +58 -0
  146. package/dist/cjs/lib/UnsetValue.d.ts +12 -0
  147. package/dist/cjs/lib/UnsetValue.js +216 -0
  148. package/dist/cjs/lib/pattern/GlobPattern.d.ts +34 -0
  149. package/dist/cjs/lib/pattern/GlobPattern.js +68 -0
  150. package/dist/cjs/lib/pattern/PatternManager.d.ts +103 -0
  151. package/dist/cjs/lib/pattern/PatternManager.js +233 -0
  152. package/dist/cjs/lib/schedule/Cron.d.ts +56 -0
  153. package/dist/cjs/lib/schedule/Cron.js +282 -0
  154. package/dist/cjs/package.json +1 -0
  155. package/dist/cjs/types/CLIContextParams.d.ts +14 -0
  156. package/dist/cjs/types/CLIContextParams.js +2 -0
  157. package/dist/cjs/types/ErrorDescription.d.ts +14 -0
  158. package/dist/cjs/types/ErrorDescription.js +2 -0
  159. package/dist/cjs/types/HTTPContextParams.d.ts +27 -0
  160. package/dist/cjs/types/HTTPContextParams.js +2 -0
  161. package/dist/cjs/types/ScheduleContextParams.d.ts +21 -0
  162. package/dist/cjs/types/ScheduleContextParams.js +2 -0
  163. package/dist/cjs/types/ServiceContextParams.d.ts +16 -0
  164. package/dist/cjs/types/ServiceContextParams.js +2 -0
  165. package/dist/esm/Entrypoint.js +985 -0
  166. package/dist/esm/adapter/commander/CommanderCLIEntrypoint.js +433 -0
  167. package/dist/esm/adapter/commander/Prompt.js +127 -0
  168. package/dist/esm/adapter/commander/Width.js +63 -0
  169. package/dist/esm/adapter/electron/ElectronIPCServiceEntrypoint.js +212 -0
  170. package/dist/esm/adapter/express/ExpressHTTPEntrypoint.js +295 -0
  171. package/dist/esm/adapter/express/Responders.js +66 -0
  172. package/dist/esm/adapter/express/StaticUI.js +96 -0
  173. package/dist/esm/adapter/fastify/FastifyHTTPEntrypoint.js +333 -0
  174. package/dist/esm/adapter/fastify/Responders.js +73 -0
  175. package/dist/esm/adapter/http/HTTPServiceEntrypoint.js +253 -0
  176. package/dist/esm/adapter/jsonrpc/JSONRPCProtocol.js +182 -0
  177. package/dist/esm/adapter/jsonrpc/JSONRPCServiceEntrypoint.js +361 -0
  178. package/dist/esm/adapter/schedule/ScheduleEntrypoint.js +272 -0
  179. package/dist/esm/adapter/socket.io/SocketIOServiceEntrypoint.js +212 -0
  180. package/dist/esm/channel/BuiltinChannels.js +125 -0
  181. package/dist/esm/channel/Channel.js +100 -0
  182. package/dist/esm/channel/EntrypointAdapter.js +39 -0
  183. package/dist/esm/context/BaseContext.js +87 -0
  184. package/dist/esm/context/CLIContext.js +49 -0
  185. package/dist/esm/context/HTTPContext.js +74 -0
  186. package/dist/esm/context/ScheduleContext.js +61 -0
  187. package/dist/esm/context/ServiceContext.js +58 -0
  188. package/dist/esm/decorators/CLIAction.js +10 -0
  189. package/dist/esm/decorators/HTTPAction.js +11 -0
  190. package/dist/esm/decorators/Prefix.js +45 -0
  191. package/dist/esm/decorators/Schedule.js +61 -0
  192. package/dist/esm/decorators/ServiceAction.js +9 -0
  193. package/dist/esm/decorators/UseMiddlewares.js +55 -0
  194. package/dist/esm/decorators/http/DELETE.js +4 -0
  195. package/dist/esm/decorators/http/GET.js +4 -0
  196. package/dist/esm/decorators/http/HEAD.js +4 -0
  197. package/dist/esm/decorators/http/OPTIONS.js +4 -0
  198. package/dist/esm/decorators/http/PATCH.js +4 -0
  199. package/dist/esm/decorators/http/POST.js +4 -0
  200. package/dist/esm/decorators/http/PUT.js +4 -0
  201. package/dist/esm/exceptions/AccessDeniedException.js +13 -0
  202. package/dist/esm/exceptions/ControllerActionNotFoundException.js +12 -0
  203. package/dist/esm/exceptions/DuplicateActionNameException.js +11 -0
  204. package/dist/esm/exceptions/EntrypointStoppedException.js +12 -0
  205. package/dist/esm/exceptions/InvalidActionGroupException.js +7 -0
  206. package/dist/esm/exceptions/InvalidChannelException.js +11 -0
  207. package/dist/esm/exceptions/InvalidEntrypointAdapterException.js +12 -0
  208. package/dist/esm/exceptions/InvalidMiddlewareException.js +11 -0
  209. package/dist/esm/exceptions/InvalidPrefixException.js +11 -0
  210. package/dist/esm/exceptions/MiddlewareNextCalledException.js +11 -0
  211. package/dist/esm/exceptions/RouteNotFoundException.js +12 -0
  212. package/dist/esm/exceptions/ServiceInvokeException.js +10 -0
  213. package/dist/esm/exports/CTRLDecorators.js +19 -0
  214. package/dist/esm/exports/Channel.js +11 -0
  215. package/dist/esm/exports/CommanderAdapter.js +1 -0
  216. package/dist/esm/exports/ElectronAdapter.js +1 -0
  217. package/dist/esm/exports/Entrypoint.js +22 -0
  218. package/dist/esm/exports/ExpressAdapter.js +3 -0
  219. package/dist/esm/exports/FastifyAdapter.js +3 -0
  220. package/dist/esm/exports/JSONRPCAdapter.js +2 -0
  221. package/dist/esm/exports/SocketIOAdapter.js +1 -0
  222. package/dist/esm/lib/AccessControl.js +204 -0
  223. package/dist/esm/lib/AccessControlRule.js +72 -0
  224. package/dist/esm/lib/ActionOptions.js +63 -0
  225. package/dist/esm/lib/ActionResult.js +24 -0
  226. package/dist/esm/lib/ApplicationOf.js +11 -0
  227. package/dist/esm/lib/Controller.js +61 -0
  228. package/dist/esm/lib/ControllerEntrypoint.js +229 -0
  229. package/dist/esm/lib/GetActionDTOAndOptions.js +46 -0
  230. package/dist/esm/lib/HTTPErrors.js +48 -0
  231. package/dist/esm/lib/Middleware.js +134 -0
  232. package/dist/esm/lib/Prefix.js +143 -0
  233. package/dist/esm/lib/Result.js +147 -0
  234. package/dist/esm/lib/ServiceResponseCodec.js +113 -0
  235. package/dist/esm/lib/StringifyPattern.js +55 -0
  236. package/dist/esm/lib/UnsetValue.js +213 -0
  237. package/dist/esm/lib/pattern/GlobPattern.js +64 -0
  238. package/dist/esm/lib/pattern/PatternManager.js +229 -0
  239. package/dist/esm/lib/schedule/Cron.js +277 -0
  240. package/dist/esm/types/CLIContextParams.js +1 -0
  241. package/dist/esm/types/ErrorDescription.js +1 -0
  242. package/dist/esm/types/HTTPContextParams.js +1 -0
  243. package/dist/esm/types/ScheduleContextParams.js +1 -0
  244. package/dist/esm/types/ServiceContextParams.js +1 -0
  245. package/dist/types/Entrypoint.d.ts +868 -0
  246. package/dist/types/adapter/commander/CommanderCLIEntrypoint.d.ts +192 -0
  247. package/dist/types/adapter/commander/Prompt.d.ts +22 -0
  248. package/dist/types/adapter/commander/Width.d.ts +12 -0
  249. package/dist/types/adapter/electron/ElectronIPCServiceEntrypoint.d.ts +203 -0
  250. package/dist/types/adapter/express/ExpressHTTPEntrypoint.d.ts +172 -0
  251. package/dist/types/adapter/express/Responders.d.ts +89 -0
  252. package/dist/types/adapter/express/StaticUI.d.ts +83 -0
  253. package/dist/types/adapter/fastify/FastifyHTTPEntrypoint.d.ts +156 -0
  254. package/dist/types/adapter/fastify/Responders.d.ts +88 -0
  255. package/dist/types/adapter/http/HTTPServiceEntrypoint.d.ts +117 -0
  256. package/dist/types/adapter/jsonrpc/JSONRPCProtocol.d.ts +194 -0
  257. package/dist/types/adapter/jsonrpc/JSONRPCServiceEntrypoint.d.ts +154 -0
  258. package/dist/types/adapter/schedule/ScheduleEntrypoint.d.ts +86 -0
  259. package/dist/types/adapter/socket.io/SocketIOServiceEntrypoint.d.ts +138 -0
  260. package/dist/types/channel/BuiltinChannels.d.ts +18 -0
  261. package/dist/types/channel/Channel.d.ts +196 -0
  262. package/dist/types/channel/EntrypointAdapter.d.ts +195 -0
  263. package/dist/types/context/BaseContext.d.ts +75 -0
  264. package/dist/types/context/CLIContext.d.ts +38 -0
  265. package/dist/types/context/HTTPContext.d.ts +52 -0
  266. package/dist/types/context/ScheduleContext.d.ts +47 -0
  267. package/dist/types/context/ServiceContext.d.ts +47 -0
  268. package/dist/types/decorators/CLIAction.d.ts +120 -0
  269. package/dist/types/decorators/HTTPAction.d.ts +178 -0
  270. package/dist/types/decorators/Prefix.d.ts +44 -0
  271. package/dist/types/decorators/Schedule.d.ts +120 -0
  272. package/dist/types/decorators/ServiceAction.d.ts +116 -0
  273. package/dist/types/decorators/UseMiddlewares.d.ts +52 -0
  274. package/dist/types/decorators/http/DELETE.d.ts +87 -0
  275. package/dist/types/decorators/http/GET.d.ts +89 -0
  276. package/dist/types/decorators/http/HEAD.d.ts +84 -0
  277. package/dist/types/decorators/http/OPTIONS.d.ts +80 -0
  278. package/dist/types/decorators/http/PATCH.d.ts +90 -0
  279. package/dist/types/decorators/http/POST.d.ts +91 -0
  280. package/dist/types/decorators/http/PUT.d.ts +92 -0
  281. package/dist/types/exceptions/AccessDeniedException.d.ts +10 -0
  282. package/dist/types/exceptions/ControllerActionNotFoundException.d.ts +9 -0
  283. package/dist/types/exceptions/DuplicateActionNameException.d.ts +8 -0
  284. package/dist/types/exceptions/EntrypointStoppedException.d.ts +9 -0
  285. package/dist/types/exceptions/InvalidActionGroupException.d.ts +4 -0
  286. package/dist/types/exceptions/InvalidChannelException.d.ts +8 -0
  287. package/dist/types/exceptions/InvalidEntrypointAdapterException.d.ts +9 -0
  288. package/dist/types/exceptions/InvalidMiddlewareException.d.ts +8 -0
  289. package/dist/types/exceptions/InvalidPrefixException.d.ts +8 -0
  290. package/dist/types/exceptions/MiddlewareNextCalledException.d.ts +8 -0
  291. package/dist/types/exceptions/RouteNotFoundException.d.ts +9 -0
  292. package/dist/types/exceptions/ServiceInvokeException.d.ts +11 -0
  293. package/dist/types/exports/CTRLDecorators.d.ts +13 -0
  294. package/dist/types/exports/Channel.d.ts +14 -0
  295. package/dist/types/exports/CommanderAdapter.d.ts +1 -0
  296. package/dist/types/exports/ElectronAdapter.d.ts +1 -0
  297. package/dist/types/exports/Entrypoint.d.ts +24 -0
  298. package/dist/types/exports/ExpressAdapter.d.ts +4 -0
  299. package/dist/types/exports/FastifyAdapter.d.ts +4 -0
  300. package/dist/types/exports/JSONRPCAdapter.d.ts +2 -0
  301. package/dist/types/exports/SocketIOAdapter.d.ts +1 -0
  302. package/dist/types/lib/AccessControl.d.ts +118 -0
  303. package/dist/types/lib/AccessControlRule.d.ts +91 -0
  304. package/dist/types/lib/ActionOptions.d.ts +67 -0
  305. package/dist/types/lib/ActionResult.d.ts +28 -0
  306. package/dist/types/lib/ApplicationOf.d.ts +6 -0
  307. package/dist/types/lib/Controller.d.ts +59 -0
  308. package/dist/types/lib/ControllerEntrypoint.d.ts +168 -0
  309. package/dist/types/lib/GetActionDTOAndOptions.d.ts +29 -0
  310. package/dist/types/lib/HTTPErrors.d.ts +55 -0
  311. package/dist/types/lib/Middleware.d.ts +146 -0
  312. package/dist/types/lib/Prefix.d.ts +98 -0
  313. package/dist/types/lib/Result.d.ts +173 -0
  314. package/dist/types/lib/ServiceResponseCodec.d.ts +82 -0
  315. package/dist/types/lib/StringifyPattern.d.ts +7 -0
  316. package/dist/types/lib/UnsetValue.d.ts +12 -0
  317. package/dist/types/lib/pattern/GlobPattern.d.ts +34 -0
  318. package/dist/types/lib/pattern/PatternManager.d.ts +103 -0
  319. package/dist/types/lib/schedule/Cron.d.ts +56 -0
  320. package/dist/types/types/CLIContextParams.d.ts +14 -0
  321. package/dist/types/types/ErrorDescription.d.ts +14 -0
  322. package/dist/types/types/HTTPContextParams.d.ts +27 -0
  323. package/dist/types/types/ScheduleContextParams.d.ts +21 -0
  324. package/dist/types/types/ServiceContextParams.d.ts +16 -0
  325. package/package.json +152 -0
@@ -0,0 +1,433 @@
1
+ import { Command, CommanderError, InvalidArgumentError, Option } from 'commander';
2
+ import { createReadStream } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { applicationOf } from '../../lib/ApplicationOf.js';
5
+ import { CLIContext } from '../../context/CLIContext.js';
6
+ import { CLIChannel } from '../../channel/BuiltinChannels.js';
7
+ import { EventsResult, FileResult, StatusResult } from '../../lib/Result.js';
8
+ import { loadPrompts, prompt } from './Prompt.js';
9
+ import { boxWrap, displayWidth } from './Width.js';
10
+ /**
11
+ * The English texts, their arguments filled
12
+ * @param text
13
+ */
14
+ function english(text) {
15
+ return text.text.replace(/\{(\w+)\}/g, (all, name) => text.params?.[name] ?? all);
16
+ }
17
+ /**
18
+ * The keys of the titles of the help of commander
19
+ */
20
+ const TITLES = {
21
+ 'Usage:': 'help.usage',
22
+ 'Arguments:': 'help.arguments',
23
+ 'Options:': 'help.options',
24
+ 'Commands:': 'help.commands',
25
+ 'Global Options:': 'help.globalOptions'
26
+ };
27
+ /**
28
+ * The type of a property, without null
29
+ * @param schema
30
+ */
31
+ function typeOf(schema) {
32
+ const types = [].concat(schema.type ?? []).filter((type) => type !== 'null');
33
+ if (types.length)
34
+ return types[0];
35
+ if (schema.enum?.length)
36
+ return typeof schema.enum[0];
37
+ return undefined;
38
+ }
39
+ /**
40
+ * The kebab case of a property name (deviceId → device-id)
41
+ * @param name
42
+ */
43
+ function kebabCase(name) {
44
+ return name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/_/g, '-').toLowerCase();
45
+ }
46
+ /**
47
+ * Parse a value of an option by its schema
48
+ * @param schema
49
+ * @param value
50
+ */
51
+ function parseValue(schema, value) {
52
+ let parsed;
53
+ switch (typeOf(schema)) {
54
+ case 'integer':
55
+ case 'number': {
56
+ parsed = Number(value);
57
+ if (value.trim() === '' || Number.isNaN(parsed))
58
+ throw new InvalidArgumentError('Not a number.');
59
+ break;
60
+ }
61
+ case 'boolean': {
62
+ if (!['true', 'false'].includes(value))
63
+ throw new InvalidArgumentError('Not a boolean.');
64
+ parsed = value === 'true';
65
+ break;
66
+ }
67
+ case 'object': {
68
+ try {
69
+ parsed = JSON.parse(value);
70
+ }
71
+ catch {
72
+ throw new InvalidArgumentError('Not a JSON object.');
73
+ }
74
+ break;
75
+ }
76
+ default:
77
+ parsed = value;
78
+ }
79
+ if (schema.enum && !schema.enum.includes(parsed))
80
+ throw new InvalidArgumentError(`Allowed choices are ${schema.enum.map((choice) => JSON.stringify(choice)).join(', ')}.`);
81
+ return parsed;
82
+ }
83
+ /**
84
+ * The option of a property
85
+ * @param property
86
+ * @param schema
87
+ * @param mandatory
88
+ * @param say the text of the help in the language of the user
89
+ * @param command the name of the command
90
+ */
91
+ function propertyOption(property, schema, mandatory, say, command) {
92
+ const flag = `--${kebabCase(property)}`;
93
+ //A boolean or a value (DTO.Alternatives(DTO.Boolean(), …)): a flag taking an optional value
94
+ const alternatives = Array.isArray(schema.anyOf) ? schema.anyOf : [];
95
+ const valued = alternatives.some((alternative) => typeOf(alternative) === 'boolean')
96
+ ? alternatives.find((alternative) => typeOf(alternative) !== 'boolean')
97
+ : undefined;
98
+ const hints = [];
99
+ const choices = schema.enum ?? schema.items?.enum ?? valued?.enum;
100
+ if (choices)
101
+ hints.push(say('help.choices', 'choices: {choices}', { choices: choices.map((choice) => JSON.stringify(choice)).join(', ') }));
102
+ if (schema.default !== undefined)
103
+ hints.push(say('help.default', 'default: {value}', { value: JSON.stringify(schema.default) }));
104
+ const text = schema.description ? say(`commands.${command}.options.${property}`, schema.description) : '';
105
+ //The hints after the description, " (default: 1)"
106
+ const description = hints.length ? `${text}${say('help.hints', ' ({hints})', { hints: hints.join(say('help.separator', ', ')) })}`.trim() : text;
107
+ //--flag gives true, --flag <value> the value
108
+ if (valued)
109
+ return [new Option(`${flag} [value]`, description).argParser((value) => parseValue(valued, value))];
110
+ const type = typeOf(schema);
111
+ if (type === 'boolean') {
112
+ const options = [new Option(flag, description)];
113
+ //A flag on by default is turned off by its negation
114
+ if (schema.default === true)
115
+ options.push(new Option(`--no-${kebabCase(property)}`, say('help.negate', 'Turn off {flag}', { flag: flag })));
116
+ return options;
117
+ }
118
+ const option = type === 'array'
119
+ ? new Option(`${flag} <values...>`, description).argParser((value, previous) => [...(Array.isArray(previous) ? previous : []), parseValue(schema.items ?? {}, value)])
120
+ : new Option(`${flag} <${type === 'object' ? 'json' : 'value'}>`, description).argParser((value) => parseValue(schema, value));
121
+ return [option.makeOptionMandatory(mandatory)];
122
+ }
123
+ /**
124
+ * The default format of a result
125
+ * @param result
126
+ */
127
+ function defaultFormat(result) {
128
+ if (result === undefined || result === null)
129
+ return undefined;
130
+ if (typeof result === 'string')
131
+ return result.endsWith('\n') ? result : `${result}\n`;
132
+ if (result instanceof Uint8Array)
133
+ return result;
134
+ return `${JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2)}\n`;
135
+ }
136
+ /**
137
+ * The message of an error
138
+ * @param error
139
+ */
140
+ function errorMessage(error) {
141
+ if (error && typeof error === 'object') {
142
+ const { errMsg, message } = error;
143
+ if (typeof errMsg === 'string' && errMsg)
144
+ return errMsg;
145
+ if (typeof message === 'string' && message)
146
+ return message;
147
+ }
148
+ return String(error);
149
+ }
150
+ /**
151
+ * Create the CLI adapter of an entrypoint, parsing the command-line arguments with commander: each CLI action
152
+ * (`@CLIAction`) becomes a command, and the properties of its input DTO become its options. It needs the optional peer
153
+ * dependency `commander` (and `@inquirer/prompts` for the interactive prompts).
154
+ *
155
+ * A property becomes a kebab-case option (`deviceId` → `--device-id <value>`), parsed by its type: a number, `true` or
156
+ * `false`, a JSON object, an array (`--tags <values...>`), a boolean as a flag (with a `--no-<name>` negation when it
157
+ * defaults to `true`); the enums, the defaults and the descriptions appear in the help. The command text may declare
158
+ * positional arguments, given to the properties of their names (`'copy <files...> [target]'`), and its leading words
159
+ * before the last one name its groups (`'package exe <file>'` is the command `exe` of the group `package`).
160
+ *
161
+ * The command runs once the application has launched (all its objects, its bootstrap and the other adapters are
162
+ * ready). Its result is written to stdout (see `format`; an `EventsResult` writes each event's data, a `FileResult`
163
+ * the file's bytes); a failure writes `error: <message>` to stderr and ends with the code 1. Then the application exits
164
+ * with the command's code (see `exit`). When the entrypoint stops first, a command not started yet does not run, and
165
+ * the prompts and the event streams end.
166
+ * @param options The adapter options; by default it parses `process.argv`, prompts in a terminal, and exits the
167
+ * application once the command ended.
168
+ * @returns The adapter, to give to the `cli` option of `buildEntrypoints`.
169
+ * @example
170
+ * ```typescript
171
+ * import {Application, DTO} from 'lakutata'
172
+ * import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
173
+ * import {CLIAction} from 'lakutata/decorator/ctrl'
174
+ * import {Expect} from 'lakutata/decorator/dto'
175
+ * import {commanderCLIEntrypoint} from 'lakutata/adapter/commander'
176
+ *
177
+ * class GreetDTO extends DTO {
178
+ * @Expect(DTO.String().required().description('The name to greet'))
179
+ * public name!: string
180
+ *
181
+ * @Expect(DTO.Number().integer().optional().default(1).description('How many times'))
182
+ * public times?: number
183
+ *
184
+ * @Expect(DTO.Boolean().optional().default(false))
185
+ * public loud?: boolean
186
+ * }
187
+ *
188
+ * class GreetController extends Controller {
189
+ * //tool greet Ada --times 2 --loud
190
+ * @CLIAction('greet <name>', GreetDTO)
191
+ * public async greet(input: GreetDTO): Promise<string> {
192
+ * const text: string = `Hello, ${input.name}`
193
+ * return (input.loud ? text.toUpperCase() : text).repeat(input.times ?? 1)
194
+ * }
195
+ * }
196
+ *
197
+ * Application.run({
198
+ * id: 'tool.app',
199
+ * name: 'Tool',
200
+ * components: {
201
+ * entrypoint: buildEntrypoints({
202
+ * controllers: [GreetController],
203
+ * cli: commanderCLIEntrypoint({bin: 'tool', description: 'A greeting tool', version: '1.0.0'})
204
+ * })
205
+ * }
206
+ * })
207
+ * ```
208
+ */
209
+ export function commanderCLIEntrypoint(options = {}) {
210
+ const stdout = options.stdout ?? process.stdout;
211
+ const stderr = options.stderr ?? process.stderr;
212
+ const stdin = options.stdin ?? process.stdin;
213
+ const format = options.format ?? defaultFormat;
214
+ //Aborts the prompts and the event streams when the adapter stops
215
+ const stopController = new AbortController();
216
+ const write = (output) => {
217
+ if (output !== undefined && output.length)
218
+ stdout.write(output);
219
+ };
220
+ /**
221
+ * Write the result of an action
222
+ * @param result
223
+ */
224
+ const output = async (result) => {
225
+ if (result instanceof EventsResult) {
226
+ return await result.producer((data) => {
227
+ if (!stopController.signal.aborted)
228
+ write(format(data));
229
+ }, stopController.signal);
230
+ }
231
+ if (result instanceof FileResult) {
232
+ const source = result.source;
233
+ if (Buffer.isBuffer(source))
234
+ return write(source);
235
+ const stream = typeof source === 'string' ? createReadStream(path.resolve(source)) : source;
236
+ return await new Promise((resolve, reject) => {
237
+ stream.once('error', reject).once('end', resolve).pipe(stdout, { end: false });
238
+ });
239
+ }
240
+ write(format(result instanceof StatusResult ? result.data : result));
241
+ };
242
+ /**
243
+ * Whether the missing options are prompted: the prompts installed (else the parser requires the options)
244
+ */
245
+ const interactive = async () => {
246
+ if (options.interactive === false)
247
+ return false;
248
+ if (options.interactive !== true && !(stdin.isTTY && stdout.isTTY))
249
+ return false;
250
+ return !!(await loadPrompts());
251
+ };
252
+ /**
253
+ * Run a command
254
+ * @param runtime
255
+ * @param action
256
+ * @param data
257
+ * @param prompting
258
+ * @param describe the description of a property in the language of the user
259
+ * @param say the text of the prompts in the language of the user
260
+ */
261
+ const execute = async (runtime, action, data, prompting, describe, say) => {
262
+ try {
263
+ if (prompting)
264
+ await prompt(action, data, { input: stdin, output: stdout, signal: stopController.signal }, describe, say);
265
+ const context = new CLIContext({ command: action.address.command, data: data });
266
+ await output(await runtime.dispatchTo(action, context));
267
+ return 0;
268
+ }
269
+ catch (error) {
270
+ stderr.write(`error: ${errorMessage(error)}\n`);
271
+ return 1;
272
+ }
273
+ };
274
+ /**
275
+ * Parse the arguments and run the command
276
+ * @param runtime
277
+ */
278
+ const run = async (runtime) => {
279
+ const argv = options.argv ?? process.argv.slice(2);
280
+ if (!argv.length && options.noCommand === 'ignore')
281
+ return undefined;
282
+ const prompting = await interactive();
283
+ //The texts of the help and of the prompts in the language of the user
284
+ const translate = options.translate ? await options.translate(runtime.module) : english;
285
+ const say = (key, text, params) => translate({ key: key, text: text, params: params });
286
+ const program = new Command(options.bin ?? path.basename(process.argv[1] ?? 'cli', path.extname(process.argv[1] ?? '')))
287
+ .exitOverride()
288
+ .configureOutput({
289
+ writeOut: (text) => stdout.write(text),
290
+ writeErr: (text) => stderr.write(text)
291
+ });
292
+ if (options.translate) {
293
+ //Inherited by the commands created next
294
+ program
295
+ .configureHelp({
296
+ styleTitle: (title) => TITLES[title] ? say(TITLES[title], title) : title,
297
+ //The widths of the wide characters (Chinese, Japanese, Korean), their lines wrapped between them
298
+ displayWidth: displayWidth,
299
+ boxWrap: (text, width) => boxWrap(text, width)
300
+ })
301
+ .helpOption('-h, --help', say('help.helpOption', 'display help for command'));
302
+ if (runtime.actions.length)
303
+ program.helpCommand('help [command]', say('help.helpCommand', 'display help for command'));
304
+ }
305
+ if (options.description)
306
+ program.description(say('description', options.description));
307
+ /**
308
+ * A group of commands, its help listing them
309
+ * @param parent
310
+ * @param group its name
311
+ * @param names the names of its groups and its own
312
+ */
313
+ const commandGroup = (parent, group, names) => {
314
+ const created = parent.command(group);
315
+ const description = options.groups?.[names.join(' ')];
316
+ if (description)
317
+ created.description(say(`commands.${names.join('.')}.description`, description));
318
+ if (options.translate)
319
+ created.helpCommand('help [command]', say('help.helpCommand', 'display help for command'));
320
+ return created;
321
+ };
322
+ if (options.version)
323
+ program.version(options.version, '-V, --version', say('help.versionOption', 'output the version number'));
324
+ let code = 0;
325
+ for (const action of runtime.actions) {
326
+ const schema = action.jsonSchema;
327
+ const required = new Set(schema.required ?? []);
328
+ //The command may declare positional arguments ("run <script>", "copy <files...> [target]"), given to the properties of their names;
329
+ //its words before them but the last are its groups ("package exe <file>": the command exe of the group package)
330
+ const words = action.address.command.trim().split(/\s+/);
331
+ const first = words.findIndex((word) => /^[<[]/.test(word));
332
+ const names = first < 0 ? words : words.slice(0, first);
333
+ let parent = program;
334
+ names.slice(0, -1).forEach((group, index) => {
335
+ parent = parent.commands.find((existing) => existing.name() === group) ?? commandGroup(parent, group, names.slice(0, index + 1));
336
+ });
337
+ const command = parent.command([names.at(-1), ...words.slice(names.length)].join(' ')).allowExcessArguments(false);
338
+ //The key of its texts: the names of its groups and its own
339
+ const name = names.join('.');
340
+ command.description(action.description ? say(`commands.${name}.description`, action.description) : action.name);
341
+ const positional = command.registeredArguments.map((argument) => argument.name());
342
+ //The description of a property: the one of its argument or of its option
343
+ const describe = (property) => {
344
+ const text = schema.properties?.[property]?.description;
345
+ return text ? say(`commands.${name}.${positional.includes(property) ? 'arguments' : 'options'}.${property}`, text) : undefined;
346
+ };
347
+ for (const argument of command.registeredArguments) {
348
+ const propertySchema = schema.properties?.[argument.name()];
349
+ if (!propertySchema)
350
+ continue;
351
+ if (propertySchema.description)
352
+ argument.description = describe(argument.name());
353
+ if (argument.variadic) {
354
+ argument.argParser((value, previous) => [...(Array.isArray(previous) ? previous : []), parseValue(propertySchema.items ?? {}, value)]);
355
+ }
356
+ else {
357
+ argument.argParser((value) => parseValue(propertySchema, value));
358
+ }
359
+ }
360
+ //The properties by the attribute names of their options
361
+ const properties = new Map();
362
+ for (const [property, propertySchema] of Object.entries(schema.properties ?? {})) {
363
+ if (positional.includes(property))
364
+ continue;
365
+ const mandatory = !prompting && required.has(property) && propertySchema.default === undefined;
366
+ for (const option of propertyOption(property, propertySchema, mandatory, say, name)) {
367
+ command.addOption(option);
368
+ properties.set(option.attributeName(), property);
369
+ }
370
+ }
371
+ command.action(async () => {
372
+ const data = {};
373
+ positional.forEach((name, index) => {
374
+ const value = command.processedArgs[index];
375
+ if (value !== undefined)
376
+ data[name] = value;
377
+ });
378
+ for (const [attribute, value] of Object.entries(command.opts())) {
379
+ if (value !== undefined && properties.has(attribute))
380
+ data[properties.get(attribute)] = value;
381
+ }
382
+ code = await execute(runtime, action, data, prompting, describe, say);
383
+ });
384
+ }
385
+ await options.configure?.(program);
386
+ try {
387
+ await program.parseAsync(argv, { from: 'user' });
388
+ }
389
+ catch (error) {
390
+ if (error instanceof CommanderError)
391
+ return error.exitCode;
392
+ throw error;
393
+ }
394
+ return code;
395
+ };
396
+ /**
397
+ * End with the code of the command
398
+ * @param runtime
399
+ * @param code
400
+ */
401
+ const exit = async (runtime, code) => {
402
+ const mode = options.exit ?? 'application';
403
+ if (typeof mode === 'function')
404
+ return await mode(code);
405
+ if (mode === 'none')
406
+ return;
407
+ const application = mode === 'application' ? applicationOf(runtime.module) : undefined;
408
+ if (application)
409
+ return application.exit(code);
410
+ process.exitCode = code;
411
+ };
412
+ return {
413
+ channel: 'cli',
414
+ definition: CLIChannel,
415
+ name: options.name,
416
+ middlewares: options.middlewares,
417
+ start: (runtime) => {
418
+ //The command runs once the application launched: every object, the bootstrap and the other adapters are ready
419
+ runtime.ready
420
+ .then(() => stopController.signal.aborted ? undefined : run(runtime))
421
+ .catch((error) => {
422
+ stderr.write(`error: ${errorMessage(error)}\n`);
423
+ return 1;
424
+ })
425
+ .then((code) => code === undefined || stopController.signal.aborted ? undefined : exit(runtime, code))
426
+ .catch((error) => stderr.write(`error: ${errorMessage(error)}\n`));
427
+ },
428
+ stop: () => {
429
+ //A command not started yet is not run, the prompts and the event streams are ended
430
+ stopController.abort();
431
+ }
432
+ };
433
+ }
@@ -0,0 +1,127 @@
1
+ import { PassThrough } from 'node:stream';
2
+ import { DTO } from '@lakutata/core';
3
+ /**
4
+ * The property names of the secrets, prompted without echo
5
+ */
6
+ const SECRET = /pass(word)?|secret|token|api[-_]?key|credential/i;
7
+ /**
8
+ * The prompts, undefined when @inquirer/prompts is not installed
9
+ */
10
+ let prompts;
11
+ /**
12
+ * Load the prompts
13
+ */
14
+ export function loadPrompts() {
15
+ prompts ??= import('@inquirer/prompts').catch(() => undefined);
16
+ return prompts;
17
+ }
18
+ /**
19
+ * The type of a property, without null
20
+ * @param schema
21
+ */
22
+ function typeOf(schema) {
23
+ const types = [].concat(schema.type ?? []).filter((type) => type !== 'null');
24
+ if (types.length)
25
+ return types[0];
26
+ if (schema.enum?.length)
27
+ return typeof schema.enum[0];
28
+ return undefined;
29
+ }
30
+ /**
31
+ * Validate an answer by the rules of its property in the DTO of the action
32
+ * @param dto
33
+ * @param property
34
+ */
35
+ function validator(dto, property) {
36
+ let field;
37
+ try {
38
+ field = dto.Schema().extract(property).label(property);
39
+ }
40
+ catch {
41
+ //A property without its own rule is validated with the whole input
42
+ return async () => true;
43
+ }
44
+ return async (value) => {
45
+ try {
46
+ await DTO.validateAsync(value, field);
47
+ return true;
48
+ }
49
+ catch (error) {
50
+ return error.errMsg ?? error.message;
51
+ }
52
+ };
53
+ }
54
+ /**
55
+ * Prompt for the required properties missing from the input of an action, when @inquirer/prompts is installed
56
+ * @param action
57
+ * @param data
58
+ * @param streams
59
+ * @param describe the description of a property in the language of the user
60
+ * @param say the text of the prompts in the language of the user
61
+ */
62
+ export async function prompt(action, data, streams, describe = (property) => action.jsonSchema.properties?.[property]?.description, say = (key, text) => text) {
63
+ const schema = action.jsonSchema;
64
+ const missing = (schema.required ?? []).filter((property) => data[property] === undefined && schema.properties?.[property]?.default === undefined);
65
+ if (!missing.length)
66
+ return;
67
+ const inquirer = await loadPrompts();
68
+ if (!inquirer)
69
+ return;
70
+ for (const property of missing) {
71
+ //A prompt ends its output once answered, the output of the adapter is kept open
72
+ const output = new PassThrough();
73
+ output.pipe(streams.output, { end: false });
74
+ try {
75
+ data[property] = await ask(inquirer, action, property, schema.properties?.[property] ?? {}, { input: streams.input, output: output, signal: streams.signal }, describe(property), say);
76
+ }
77
+ finally {
78
+ output.unpipe(streams.output);
79
+ }
80
+ }
81
+ }
82
+ /**
83
+ * Ask for a property
84
+ * @param inquirer
85
+ * @param action
86
+ * @param property
87
+ * @param propertySchema
88
+ * @param context
89
+ * @param description the description of the property in the language of the user
90
+ * @param say the text of the prompts in the language of the user
91
+ */
92
+ async function ask(inquirer, action, property, propertySchema, context, description, say) {
93
+ const message = description ? `${description} (${property})` : property;
94
+ const validate = validator(action.dto, property);
95
+ const type = typeOf(propertySchema);
96
+ const choices = (values) => values.map((value) => ({ name: String(value), value: value }));
97
+ if (type === 'boolean')
98
+ return await inquirer.confirm({ message: message }, context);
99
+ if (propertySchema.enum)
100
+ return await inquirer.select({ message: message, choices: choices(propertySchema.enum) }, context);
101
+ if (type === 'array' && propertySchema.items?.enum)
102
+ return await inquirer.checkbox({ message: message, choices: choices(propertySchema.items.enum), validate: (selected) => validate(selected.map((choice) => choice.value)) }, context);
103
+ if (type === 'number' || type === 'integer')
104
+ return await inquirer.number({ message: message, required: true, step: type === 'integer' ? 1 : 'any', validate: validate }, context);
105
+ if (type === 'string' && (propertySchema.format === 'password' || SECRET.test(property)))
106
+ return await inquirer.password({ message: message, mask: '*', validate: validate }, context);
107
+ //The arrays are separated by commas, the objects are written in JSON
108
+ const parse = (answer) => {
109
+ if (type === 'array')
110
+ return answer.split(',').map((item) => item.trim()).filter((item) => !!item);
111
+ if (type === 'object')
112
+ return JSON.parse(answer);
113
+ return answer;
114
+ };
115
+ return parse(await inquirer.input({
116
+ message: message,
117
+ required: true,
118
+ validate: async (value) => {
119
+ try {
120
+ return await validate(parse(value));
121
+ }
122
+ catch {
123
+ return say('prompt.json', 'Not a JSON object');
124
+ }
125
+ }
126
+ }, context));
127
+ }
@@ -0,0 +1,63 @@
1
+ import { stripVTControlCharacters } from 'node:util';
2
+ /**
3
+ * The wide characters of the terminals: the Chinese, Japanese and Korean ones, the full width forms
4
+ */
5
+ const WIDE = '\\u1100-\\u115F\\u2E80-\\u303E\\u3041-\\u33FF\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uA000-\\uA4CF\\uAC00-\\uD7A3\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFF60\\uFFE0-\\uFFE6\\u{20000}-\\u{3FFFD}';
6
+ /**
7
+ * The punctuation which does not start a line
8
+ */
9
+ const CLOSING = '、。,.:;!?)」』】〕〉》%,.:;!?)\\]}';
10
+ /**
11
+ * The punctuation which does not end a line
12
+ */
13
+ const OPENING = '(「『【〔〈《(\\[{';
14
+ const WIDE_CHARACTER = new RegExp(`[${WIDE}]`, 'u');
15
+ /**
16
+ * The chunks of a line the wrapping keeps whole: a word, or a wide character, with the punctuation opening and
17
+ * closing it
18
+ */
19
+ const CHUNK = new RegExp(`\\s*[${OPENING}]*(?:[${WIDE}]|[^\\s${WIDE}]+)[${CLOSING}]*`, 'gu');
20
+ /**
21
+ * The width of a text in a terminal, the wide characters taking two columns
22
+ * @param text
23
+ */
24
+ export function displayWidth(text) {
25
+ let width = 0;
26
+ for (const character of stripVTControlCharacters(text))
27
+ width += WIDE_CHARACTER.test(character) ? 2 : 1;
28
+ return width;
29
+ }
30
+ /**
31
+ * Wrap a text to a width, as commander does, the lines of wide characters wrapped between them
32
+ * @param text
33
+ * @param width
34
+ * @param minimum the width under which the text is not wrapped
35
+ */
36
+ export function boxWrap(text, width, minimum = 40) {
37
+ if (width < minimum)
38
+ return text;
39
+ const wrapped = [];
40
+ for (const line of text.split(/\r\n|\n/)) {
41
+ const chunks = line.match(CHUNK);
42
+ if (!chunks) {
43
+ wrapped.push('');
44
+ continue;
45
+ }
46
+ let current = chunks.shift();
47
+ let currentWidth = displayWidth(current);
48
+ for (const chunk of chunks) {
49
+ const chunkWidth = displayWidth(chunk);
50
+ if (currentWidth + chunkWidth <= width) {
51
+ current += chunk;
52
+ currentWidth += chunkWidth;
53
+ continue;
54
+ }
55
+ wrapped.push(current);
56
+ //The space at the break removed
57
+ current = chunk.trimStart();
58
+ currentWidth = displayWidth(current);
59
+ }
60
+ wrapped.push(current);
61
+ }
62
+ return wrapped.join('\n');
63
+ }