git-remote-ops 0.1.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 (245) hide show
  1. package/AGENTS.md +177 -0
  2. package/LICENSE +21 -0
  3. package/README.md +247 -0
  4. package/esm/_dnt.shims.js +72 -0
  5. package/esm/cli.js +217 -0
  6. package/esm/client.js +439 -0
  7. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_argument_types.js +1 -0
  8. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_errors.js +133 -0
  9. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_spread.js +1 -0
  10. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_type_utils.js +1 -0
  11. package/esm/deps/jsr.io/@cliffy/command/1.1.0/_utils.js +141 -0
  12. package/esm/deps/jsr.io/@cliffy/command/1.1.0/command.js +1861 -0
  13. package/esm/deps/jsr.io/@cliffy/command/1.1.0/help/_help_generator.js +357 -0
  14. package/esm/deps/jsr.io/@cliffy/command/1.1.0/mod.js +13 -0
  15. package/esm/deps/jsr.io/@cliffy/command/1.1.0/type.js +27 -0
  16. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/action_list.js +16 -0
  17. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/boolean.js +13 -0
  18. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/child_command.js +14 -0
  19. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/command.js +9 -0
  20. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/enum.js +24 -0
  21. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/file.js +12 -0
  22. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/integer.js +9 -0
  23. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/number.js +9 -0
  24. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/secret.js +7 -0
  25. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types/string.js +9 -0
  26. package/esm/deps/jsr.io/@cliffy/command/1.1.0/types.js +2 -0
  27. package/esm/deps/jsr.io/@cliffy/command/1.1.0/upgrade/_check_version.js +26 -0
  28. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/_errors.js +129 -0
  29. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/_utils.js +100 -0
  30. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/_validate_flags.js +166 -0
  31. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/flags.js +750 -0
  32. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/mod.js +55 -0
  33. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/boolean.js +11 -0
  34. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/integer.js +9 -0
  35. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/number.js +11 -0
  36. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types/string.js +4 -0
  37. package/esm/deps/jsr.io/@cliffy/flags/1.1.0/types.js +1 -0
  38. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/exit.js +16 -0
  39. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_args.js +11 -0
  40. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_columns.js +25 -0
  41. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_env.js +18 -0
  42. package/esm/deps/jsr.io/@cliffy/internal/1.1.0/runtime/inspect.js +11 -0
  43. package/esm/deps/jsr.io/@cliffy/table/1.1.0/_layout.js +616 -0
  44. package/esm/deps/jsr.io/@cliffy/table/1.1.0/_utils.js +79 -0
  45. package/esm/deps/jsr.io/@cliffy/table/1.1.0/border.js +18 -0
  46. package/esm/deps/jsr.io/@cliffy/table/1.1.0/cell.js +190 -0
  47. package/esm/deps/jsr.io/@cliffy/table/1.1.0/column.js +117 -0
  48. package/esm/deps/jsr.io/@cliffy/table/1.1.0/consume_words.js +64 -0
  49. package/esm/deps/jsr.io/@cliffy/table/1.1.0/mod.js +42 -0
  50. package/esm/deps/jsr.io/@cliffy/table/1.1.0/row.js +82 -0
  51. package/esm/deps/jsr.io/@cliffy/table/1.1.0/table.js +341 -0
  52. package/esm/deps/jsr.io/@cliffy/table/1.1.0/unicode_width.js +101 -0
  53. package/esm/deps/jsr.io/@std/crypto/1.1.0/_types.js +2 -0
  54. package/esm/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.internal.js +237 -0
  55. package/esm/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.js +2277 -0
  56. package/esm/deps/jsr.io/@std/crypto/1.1.0/_wasm/mod.js +46 -0
  57. package/esm/deps/jsr.io/@std/crypto/1.1.0/aes_gcm.js +132 -0
  58. package/esm/deps/jsr.io/@std/crypto/1.1.0/crypto.js +270 -0
  59. package/esm/deps/jsr.io/@std/crypto/1.1.0/mod.js +23 -0
  60. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +61 -0
  61. package/esm/deps/jsr.io/@std/encoding/1.0.10/_common16.js +51 -0
  62. package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.js +13 -0
  63. package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.js +2 -0
  64. package/esm/deps/jsr.io/@std/encoding/1.0.10/hex.js +87 -0
  65. package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.js +903 -0
  66. package/esm/deps/jsr.io/@std/text/1.0.18/closest_string.js +46 -0
  67. package/esm/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.js +127 -0
  68. package/esm/errors.js +38 -0
  69. package/esm/index.js +10 -0
  70. package/esm/logger.js +216 -0
  71. package/esm/objects/commit.js +47 -0
  72. package/esm/objects/index.js +2 -0
  73. package/esm/objects/tree.js +149 -0
  74. package/esm/pack/delta.js +179 -0
  75. package/esm/pack/index.js +3 -0
  76. package/esm/pack/objects.js +72 -0
  77. package/esm/pack/parser.js +304 -0
  78. package/esm/package.json +3 -0
  79. package/esm/protocol/index.js +3 -0
  80. package/esm/protocol/pkt_line.js +103 -0
  81. package/esm/protocol/refs.js +100 -0
  82. package/esm/protocol/upload_pack.js +259 -0
  83. package/esm/transport.js +128 -0
  84. package/esm/types.js +8 -0
  85. package/package.json +50 -0
  86. package/types/_dnt.shims.d.ts +16 -0
  87. package/types/_dnt.shims.d.ts.map +1 -0
  88. package/types/cli.d.ts +3 -0
  89. package/types/cli.d.ts.map +1 -0
  90. package/types/client.d.ts +108 -0
  91. package/types/client.d.ts.map +1 -0
  92. package/types/deps/jsr.io/@cliffy/command/1.1.0/_argument_types.d.ts +163 -0
  93. package/types/deps/jsr.io/@cliffy/command/1.1.0/_argument_types.d.ts.map +1 -0
  94. package/types/deps/jsr.io/@cliffy/command/1.1.0/_errors.d.ts +71 -0
  95. package/types/deps/jsr.io/@cliffy/command/1.1.0/_errors.d.ts.map +1 -0
  96. package/types/deps/jsr.io/@cliffy/command/1.1.0/_spread.d.ts +16 -0
  97. package/types/deps/jsr.io/@cliffy/command/1.1.0/_spread.d.ts.map +1 -0
  98. package/types/deps/jsr.io/@cliffy/command/1.1.0/_type_utils.d.ts +15 -0
  99. package/types/deps/jsr.io/@cliffy/command/1.1.0/_type_utils.d.ts.map +1 -0
  100. package/types/deps/jsr.io/@cliffy/command/1.1.0/_utils.d.ts +38 -0
  101. package/types/deps/jsr.io/@cliffy/command/1.1.0/_utils.d.ts.map +1 -0
  102. package/types/deps/jsr.io/@cliffy/command/1.1.0/command.d.ts +1086 -0
  103. package/types/deps/jsr.io/@cliffy/command/1.1.0/command.d.ts.map +1 -0
  104. package/types/deps/jsr.io/@cliffy/command/1.1.0/help/_help_generator.d.ts +33 -0
  105. package/types/deps/jsr.io/@cliffy/command/1.1.0/help/_help_generator.d.ts.map +1 -0
  106. package/types/deps/jsr.io/@cliffy/command/1.1.0/mod.d.ts +78 -0
  107. package/types/deps/jsr.io/@cliffy/command/1.1.0/mod.d.ts.map +1 -0
  108. package/types/deps/jsr.io/@cliffy/command/1.1.0/type.d.ts +51 -0
  109. package/types/deps/jsr.io/@cliffy/command/1.1.0/type.d.ts.map +1 -0
  110. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/action_list.d.ts +10 -0
  111. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/action_list.d.ts.map +1 -0
  112. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/boolean.d.ts +10 -0
  113. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/boolean.d.ts.map +1 -0
  114. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/child_command.d.ts +10 -0
  115. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/child_command.d.ts.map +1 -0
  116. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/command.d.ts +8 -0
  117. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/command.d.ts.map +1 -0
  118. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/enum.d.ts +11 -0
  119. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/enum.d.ts.map +1 -0
  120. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/file.d.ts +6 -0
  121. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/file.d.ts.map +1 -0
  122. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/integer.d.ts +8 -0
  123. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/integer.d.ts.map +1 -0
  124. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/number.d.ts +8 -0
  125. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/number.d.ts.map +1 -0
  126. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/secret.d.ts +6 -0
  127. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/secret.d.ts.map +1 -0
  128. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/string.d.ts +8 -0
  129. package/types/deps/jsr.io/@cliffy/command/1.1.0/types/string.d.ts.map +1 -0
  130. package/types/deps/jsr.io/@cliffy/command/1.1.0/types.d.ts +161 -0
  131. package/types/deps/jsr.io/@cliffy/command/1.1.0/types.d.ts.map +1 -0
  132. package/types/deps/jsr.io/@cliffy/command/1.1.0/upgrade/_check_version.d.ts +4 -0
  133. package/types/deps/jsr.io/@cliffy/command/1.1.0/upgrade/_check_version.d.ts.map +1 -0
  134. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_errors.d.ts +67 -0
  135. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_errors.d.ts.map +1 -0
  136. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_utils.d.ts +17 -0
  137. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_utils.d.ts.map +1 -0
  138. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_validate_flags.d.ts +11 -0
  139. package/types/deps/jsr.io/@cliffy/flags/1.1.0/_validate_flags.d.ts.map +1 -0
  140. package/types/deps/jsr.io/@cliffy/flags/1.1.0/flags.d.ts +154 -0
  141. package/types/deps/jsr.io/@cliffy/flags/1.1.0/flags.d.ts.map +1 -0
  142. package/types/deps/jsr.io/@cliffy/flags/1.1.0/mod.d.ts +57 -0
  143. package/types/deps/jsr.io/@cliffy/flags/1.1.0/mod.d.ts.map +1 -0
  144. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/boolean.d.ts +4 -0
  145. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/boolean.d.ts.map +1 -0
  146. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/integer.d.ts +4 -0
  147. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/integer.d.ts.map +1 -0
  148. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/number.d.ts +4 -0
  149. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/number.d.ts.map +1 -0
  150. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/string.d.ts +4 -0
  151. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types/string.d.ts.map +1 -0
  152. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types.d.ts +170 -0
  153. package/types/deps/jsr.io/@cliffy/flags/1.1.0/types.d.ts.map +1 -0
  154. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/exit.d.ts +8 -0
  155. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/exit.d.ts.map +1 -0
  156. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_args.d.ts +7 -0
  157. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_args.d.ts.map +1 -0
  158. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_columns.d.ts +7 -0
  159. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_columns.d.ts.map +1 -0
  160. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_env.d.ts +8 -0
  161. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/get_env.d.ts.map +1 -0
  162. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/inspect.d.ts +7 -0
  163. package/types/deps/jsr.io/@cliffy/internal/1.1.0/runtime/inspect.d.ts.map +1 -0
  164. package/types/deps/jsr.io/@cliffy/table/1.1.0/_layout.d.ts +108 -0
  165. package/types/deps/jsr.io/@cliffy/table/1.1.0/_layout.d.ts.map +1 -0
  166. package/types/deps/jsr.io/@cliffy/table/1.1.0/_utils.d.ts +26 -0
  167. package/types/deps/jsr.io/@cliffy/table/1.1.0/_utils.d.ts.map +1 -0
  168. package/types/deps/jsr.io/@cliffy/table/1.1.0/border.d.ts +21 -0
  169. package/types/deps/jsr.io/@cliffy/table/1.1.0/border.d.ts.map +1 -0
  170. package/types/deps/jsr.io/@cliffy/table/1.1.0/cell.d.ts +155 -0
  171. package/types/deps/jsr.io/@cliffy/table/1.1.0/cell.d.ts.map +1 -0
  172. package/types/deps/jsr.io/@cliffy/table/1.1.0/column.d.ts +97 -0
  173. package/types/deps/jsr.io/@cliffy/table/1.1.0/column.d.ts.map +1 -0
  174. package/types/deps/jsr.io/@cliffy/table/1.1.0/consume_words.d.ts +30 -0
  175. package/types/deps/jsr.io/@cliffy/table/1.1.0/consume_words.d.ts.map +1 -0
  176. package/types/deps/jsr.io/@cliffy/table/1.1.0/mod.d.ts +43 -0
  177. package/types/deps/jsr.io/@cliffy/table/1.1.0/mod.d.ts.map +1 -0
  178. package/types/deps/jsr.io/@cliffy/table/1.1.0/row.d.ts +67 -0
  179. package/types/deps/jsr.io/@cliffy/table/1.1.0/row.d.ts.map +1 -0
  180. package/types/deps/jsr.io/@cliffy/table/1.1.0/table.d.ts +235 -0
  181. package/types/deps/jsr.io/@cliffy/table/1.1.0/table.d.ts.map +1 -0
  182. package/types/deps/jsr.io/@cliffy/table/1.1.0/unicode_width.d.ts +40 -0
  183. package/types/deps/jsr.io/@cliffy/table/1.1.0/unicode_width.d.ts.map +1 -0
  184. package/types/deps/jsr.io/@std/crypto/1.1.0/_types.d.ts +9 -0
  185. package/types/deps/jsr.io/@std/crypto/1.1.0/_types.d.ts.map +1 -0
  186. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.d.ts +2 -0
  187. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.d.ts.map +1 -0
  188. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.internal.d.ts +69 -0
  189. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/lib/deno_std_wasm_crypto.internal.d.ts.map +1 -0
  190. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/mod.d.ts +13 -0
  191. package/types/deps/jsr.io/@std/crypto/1.1.0/_wasm/mod.d.ts.map +1 -0
  192. package/types/deps/jsr.io/@std/crypto/1.1.0/aes_gcm.d.ts +76 -0
  193. package/types/deps/jsr.io/@std/crypto/1.1.0/aes_gcm.d.ts.map +1 -0
  194. package/types/deps/jsr.io/@std/crypto/1.1.0/crypto.d.ts +149 -0
  195. package/types/deps/jsr.io/@std/crypto/1.1.0/crypto.d.ts.map +1 -0
  196. package/types/deps/jsr.io/@std/crypto/1.1.0/mod.d.ts +22 -0
  197. package/types/deps/jsr.io/@std/crypto/1.1.0/mod.d.ts.map +1 -0
  198. package/types/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +40 -0
  199. package/types/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts.map +1 -0
  200. package/types/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts +23 -0
  201. package/types/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts.map +1 -0
  202. package/types/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts +4 -0
  203. package/types/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +1 -0
  204. package/types/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts +9 -0
  205. package/types/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +1 -0
  206. package/types/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts +39 -0
  207. package/types/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts.map +1 -0
  208. package/types/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts +700 -0
  209. package/types/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts.map +1 -0
  210. package/types/deps/jsr.io/@std/text/1.0.18/closest_string.d.ts +42 -0
  211. package/types/deps/jsr.io/@std/text/1.0.18/closest_string.d.ts.map +1 -0
  212. package/types/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.d.ts +23 -0
  213. package/types/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.d.ts.map +1 -0
  214. package/types/errors.d.ts +73 -0
  215. package/types/errors.d.ts.map +1 -0
  216. package/types/index.d.ts +14 -0
  217. package/types/index.d.ts.map +1 -0
  218. package/types/logger.d.ts +70 -0
  219. package/types/logger.d.ts.map +1 -0
  220. package/types/objects/commit.d.ts +23 -0
  221. package/types/objects/commit.d.ts.map +1 -0
  222. package/types/objects/index.d.ts +3 -0
  223. package/types/objects/index.d.ts.map +1 -0
  224. package/types/objects/tree.d.ts +49 -0
  225. package/types/objects/tree.d.ts.map +1 -0
  226. package/types/pack/delta.d.ts +47 -0
  227. package/types/pack/delta.d.ts.map +1 -0
  228. package/types/pack/index.d.ts +4 -0
  229. package/types/pack/index.d.ts.map +1 -0
  230. package/types/pack/objects.d.ts +53 -0
  231. package/types/pack/objects.d.ts.map +1 -0
  232. package/types/pack/parser.d.ts +61 -0
  233. package/types/pack/parser.d.ts.map +1 -0
  234. package/types/protocol/index.d.ts +4 -0
  235. package/types/protocol/index.d.ts.map +1 -0
  236. package/types/protocol/pkt_line.d.ts +44 -0
  237. package/types/protocol/pkt_line.d.ts.map +1 -0
  238. package/types/protocol/refs.d.ts +40 -0
  239. package/types/protocol/refs.d.ts.map +1 -0
  240. package/types/protocol/upload_pack.d.ts +45 -0
  241. package/types/protocol/upload_pack.d.ts.map +1 -0
  242. package/types/transport.d.ts +24 -0
  243. package/types/transport.d.ts.map +1 -0
  244. package/types/types.d.ts +121 -0
  245. package/types/types.d.ts.map +1 -0
@@ -0,0 +1,1861 @@
1
+ // deno-lint-ignore-file no-explicit-any
2
+ import { parseFlags, UnknownTypeError, ValidationError as FlagsValidationError, } from "../../flags/1.1.0/mod.js";
3
+ import { bold, brightBlue, red } from "../../../@std/fmt/1.0.10/colors.js";
4
+ import { CommandNotFoundError, DefaultCommandNotFoundError, DuplicateCommandAliasError, DuplicateCommandNameError, DuplicateCompletionError, DuplicateEnvVarError, DuplicateExampleError, DuplicateOptionNameError, DuplicateTypeError, MissingCommandNameError, MissingRequiredEnvVarError, NoArgumentsAllowedError, TooManyArgumentsError, TooManyEnvVarValuesError, UnexpectedOptionalEnvVarValueError, UnexpectedVariadicEnvVarValueError, UnknownCommandError, ValidationError, } from "./_errors.js";
5
+ import { exit } from "../../internal/1.1.0/runtime/exit.js";
6
+ import { getArgs } from "../../internal/1.1.0/runtime/get_args.js";
7
+ import { getEnv } from "../../internal/1.1.0/runtime/get_env.js";
8
+ import { getDescription, parseArgumentsDefinition, splitArguments, underscoreToCamelCase, } from "./_utils.js";
9
+ import { HelpGenerator } from "./help/_help_generator.js";
10
+ import { Type } from "./type.js";
11
+ import { BooleanType } from "./types/boolean.js";
12
+ import { FileType } from "./types/file.js";
13
+ import { IntegerType } from "./types/integer.js";
14
+ import { NumberType } from "./types/number.js";
15
+ import { SecretType } from "./types/secret.js";
16
+ import { StringType } from "./types/string.js";
17
+ import { checkVersion } from "./upgrade/_check_version.js";
18
+ /**
19
+ * Chainable command factory class.
20
+ *
21
+ * The command class can be used to create main and sub commands. All methods
22
+ * from the command class are chainable. Options, arguments, types, etc. that
23
+ * belong to the main command, should be registered before the first sub-command
24
+ * is registered. All options, arguments, etc. that are registered after calling
25
+ * the `.command()` method will be registered to that child-command.
26
+ *
27
+ * When calling the `.reset()` method, options, arguments, etc. will be
28
+ * registered again to the main command.
29
+ *
30
+ * @example Todo cli
31
+ *
32
+ * ```ts
33
+ * import { Command } from "./mod.ts";
34
+ *
35
+ * export const cli = new Command()
36
+ * .name("todo")
37
+ * .description("Todo cli.")
38
+ * .globalOption("--verbose", "Enable verbose output.")
39
+ * .globalEnv("VERBOSE=<value>", "Enable verbose output.")
40
+ * .command("add <todo>", "Add todo.")
41
+ * .action(({ verbose }, todo: string) => {
42
+ * if (verbose) {
43
+ * console.log("Add todo '%s'.", todo);
44
+ * }
45
+ * })
46
+ * .command("delete <id>", "Delete todo.")
47
+ * .action(({ verbose }, id: string) => {
48
+ * if (verbose) {
49
+ * console.log("Delete todo with id '%s'.", id);
50
+ * }
51
+ * });
52
+ *
53
+ * if (import.meta.main) {
54
+ * await cli.parse();
55
+ * }
56
+ * ```
57
+ *
58
+ * @example Use command instance as child command
59
+ *
60
+ * ```ts
61
+ * import { Command } from "./mod.ts";
62
+ *
63
+ * export const addCommand = new Command<{ verbose?: boolean }>()
64
+ * .description("Add todo.")
65
+ * .arguments("<todo>")
66
+ * .action(({ verbose }, todo: string) => {
67
+ * if (verbose) {
68
+ * console.log("Add todo '%s'.", todo);
69
+ * }
70
+ * });
71
+ *
72
+ * export const deleteCommand = new Command<{ verbose?: boolean }>()
73
+ * .description("Delete todo.")
74
+ * .arguments("<id>")
75
+ * .action(({ verbose }, id: string) => {
76
+ * if (verbose) {
77
+ * console.log("Delete todo with id '%s'.", id);
78
+ * }
79
+ * });
80
+ *
81
+ * export const cli = new Command()
82
+ * .name("todo")
83
+ * .description("Todo cli.")
84
+ * .globalOption("--verbose", "Enable verbose output.")
85
+ * .globalEnv("VERBOSE=<value:boolean>", "Enable verbose output.")
86
+ * .command("add", addCommand)
87
+ * .command("delete", deleteCommand);
88
+ *
89
+ * if (import.meta.main) {
90
+ * await cli.parse();
91
+ * }
92
+ * ```
93
+ */
94
+ export class Command {
95
+ cmd = this;
96
+ parent;
97
+ props = {
98
+ rawArgs: [],
99
+ literalArgs: [],
100
+ args: [],
101
+ };
102
+ settings = {
103
+ name: "COMMAND",
104
+ description: "",
105
+ examples: [],
106
+ aliases: [],
107
+ meta: {},
108
+ commands: new Map(),
109
+ };
110
+ builder = {
111
+ groupName: null,
112
+ types: new Map(),
113
+ options: [],
114
+ envVars: [],
115
+ completions: new Map(),
116
+ };
117
+ versionOption(flags, desc, opts) {
118
+ this.settings.versionOptions = flags === false ? flags : {
119
+ flags,
120
+ desc,
121
+ opts: typeof opts === "function" ? { action: opts } : opts,
122
+ };
123
+ return this;
124
+ }
125
+ helpOption(flags, desc, opts) {
126
+ this.settings.helpOptions = flags === false ? flags : {
127
+ flags,
128
+ desc,
129
+ opts: typeof opts === "function" ? { action: opts } : opts,
130
+ };
131
+ return this;
132
+ }
133
+ /**
134
+ * Add new sub-command.
135
+ * @param nameAndArguments Command definition. E.g: `my-command <input-file:string> <output-file:string>`
136
+ * @param cmdOrDescription The description of the new child command.
137
+ * @param options Sub-command options.
138
+ */
139
+ command(nameAndArguments, cmdOrDescription, { override } = {}) {
140
+ this.reset();
141
+ const result = splitArguments(nameAndArguments);
142
+ const name = result.flags.shift();
143
+ const aliases = result.flags;
144
+ if (!name) {
145
+ throw new MissingCommandNameError();
146
+ }
147
+ if (this.getBaseCommand(name, true)) {
148
+ if (!override) {
149
+ throw new DuplicateCommandNameError(name);
150
+ }
151
+ this.removeCommand(name);
152
+ }
153
+ let description;
154
+ let cmd;
155
+ if (typeof cmdOrDescription === "string") {
156
+ description = cmdOrDescription;
157
+ }
158
+ if (cmdOrDescription instanceof Command) {
159
+ cmd = cmdOrDescription.reset();
160
+ }
161
+ else {
162
+ cmd = new Command();
163
+ }
164
+ cmd.settings.name = name;
165
+ cmd.parent = this;
166
+ if (description) {
167
+ cmd.description(description);
168
+ }
169
+ if (result.typeDefinition) {
170
+ cmd.arguments(result.typeDefinition);
171
+ }
172
+ aliases.forEach((alias) => cmd.alias(alias));
173
+ this.settings.commands.set(name, cmd);
174
+ this.select(name);
175
+ return this;
176
+ }
177
+ /**
178
+ * Add new command alias.
179
+ *
180
+ * @param alias Tha name of the alias.
181
+ */
182
+ alias(alias) {
183
+ if (this.cmd.settings.name === alias ||
184
+ this.cmd.settings.aliases.includes(alias)) {
185
+ throw new DuplicateCommandAliasError(alias);
186
+ }
187
+ this.cmd.settings.aliases.push(alias);
188
+ return this;
189
+ }
190
+ /** Reset internal command reference to main command. */
191
+ reset() {
192
+ this.builder.groupName = null;
193
+ this.cmd = this;
194
+ return this;
195
+ }
196
+ /**
197
+ * Set internal command pointer to child command with given name.
198
+ * @param name The name of the command to select.
199
+ */
200
+ select(name) {
201
+ const cmd = this.getBaseCommand(name, true);
202
+ if (!cmd) {
203
+ throw new CommandNotFoundError(name, this.getBaseCommands(true));
204
+ }
205
+ this.cmd = cmd;
206
+ return this;
207
+ }
208
+ /*****************************************************************************
209
+ **** SUB HANDLER ************************************************************
210
+ *****************************************************************************/
211
+ /**
212
+ * Set command name.
213
+ *
214
+ * This method is usually used to set the command name for the main command.
215
+ * The name should match the name of your program. It is displayed in the auto
216
+ * generated help and used for shell completions by default.
217
+ *
218
+ * When used on child command, the name will be overridden by the command name
219
+ * passed to the parent command when the command is registered with the
220
+ * {@linkcode Command.command}.
221
+ *
222
+ * @param name The name for the command.
223
+ */
224
+ name(name) {
225
+ this.cmd.settings.name = name;
226
+ return this;
227
+ }
228
+ /**
229
+ * Set command version.
230
+ *
231
+ * Set the version of your cli. The version is displayed in the auto generated
232
+ * help and the output from the [version](./help.md#version-option) option.
233
+ *
234
+ * @param version Semantic version string string or method that returns the version string.
235
+ */
236
+ version(version) {
237
+ if (typeof version === "string") {
238
+ this.cmd.settings.version = () => version;
239
+ }
240
+ else if (typeof version === "function") {
241
+ this.cmd.settings.version = version;
242
+ }
243
+ return this;
244
+ }
245
+ /**
246
+ * Add meta data. Will be displayed in the auto generated help and in the
247
+ * output of the long version.
248
+ *
249
+ * @param name The name/label of the metadata.
250
+ * @param value The value of the metadata.
251
+ */
252
+ meta(name, value) {
253
+ this.cmd.settings.meta[name] = value;
254
+ return this;
255
+ }
256
+ getMeta(name) {
257
+ return typeof name === "undefined"
258
+ ? this.settings.meta
259
+ : this.settings.meta[name];
260
+ }
261
+ /**
262
+ * Set help options or define a custom help handler or help string.
263
+ *
264
+ * @param help Options for the build-in help generator or a custom help string
265
+ * or function that generates the help string. If the help is a function, it
266
+ * receives the command instance and the help options as parameters and should
267
+ * return the help string. If the help is a string, it is returned as is when
268
+ * the help is called.
269
+ * @param customHelpOptions Custom help options. If the first parameter is an
270
+ * object, it is treated as custom help options and the default help generator
271
+ * will be used to generate the help text based on these options.
272
+ *
273
+ * @example Help options
274
+ *
275
+ * ```ts
276
+ * import { Command } from "@cliffy/command";
277
+ *
278
+ * await new Command()
279
+ * .name("demo")
280
+ * .help({ auto: true })
281
+ * .parse();
282
+ * ```
283
+ *
284
+ * @example Custom help string
285
+ *
286
+ * ```ts
287
+ * import { Command } from "@cliffy/command";
288
+ *
289
+ * await new Command()
290
+ * .name("demo")
291
+ * .help("This is a custom help string.")
292
+ * .parse();
293
+ * ```
294
+ *
295
+ * @example Custom help handler
296
+ *
297
+ * ```ts
298
+ * import { Command } from "@cliffy/command";
299
+ *
300
+ * await new Command()
301
+ * .name("demo")
302
+ * .help((cmd) => {
303
+ * return `This is a custom help string for command ${cmd.getName()}.`;
304
+ * })
305
+ * .parse();
306
+ * ```
307
+ *
308
+ * @example Help help handler with options
309
+ *
310
+ * ```ts
311
+ * import { Command } from "@cliffy/command";
312
+ *
313
+ * await new Command()
314
+ * .name("demo")
315
+ * .help(
316
+ * (cmd, options) => {
317
+ * return `This is a custom help string for command ${cmd.getName()} with options: ${JSON.stringify(options)}.`;
318
+ * },
319
+ * { auto: true },
320
+ * )
321
+ * .parse();
322
+ * ```
323
+ */
324
+ help(help, customHelpOptions) {
325
+ if (typeof help === "string") {
326
+ this.cmd.settings.help = () => help;
327
+ }
328
+ else if (typeof help === "function") {
329
+ this.cmd.settings.help = help;
330
+ }
331
+ else {
332
+ customHelpOptions = help;
333
+ this.cmd.settings.help = (cmd, options) => HelpGenerator.generate(cmd, { ...help, ...options });
334
+ }
335
+ this.cmd.settings.autoHelp = customHelpOptions?.auto;
336
+ return this;
337
+ }
338
+ /**
339
+ * Set the command description.
340
+ *
341
+ * The description will be displayed in the auto generated help. If the help
342
+ * option is called with the short flag `-h`, only the first line is
343
+ * displayed. If called with the long name `--help`, the full description is
344
+ * displayed.
345
+ *
346
+ * For better multiline formatting, unnecessary indentations and empty leading
347
+ * and trailing lines will be automatically removed.
348
+ *
349
+ * @example Multiline formatting
350
+ *
351
+ * For example, following description:
352
+ *
353
+ * ```ts
354
+ * import { Command } from "https://deno.land/x/cliffy/command/mod.ts";
355
+ *
356
+ * new Command()
357
+ * .description(`
358
+ * This is a multiline description.
359
+ * The indentation of this line will be preserved.
360
+ * `);
361
+ * ```
362
+ *
363
+ * is formatted as follows:
364
+ *
365
+ * ```console
366
+ * This is a multiline description.
367
+ * The indentation of this line will be preserved.
368
+ * ```
369
+ *
370
+ * @param description The command description.
371
+ */
372
+ description(description) {
373
+ this.cmd.settings.description = description;
374
+ return this;
375
+ }
376
+ /**
377
+ * Set the command usage. Defaults to arguments.
378
+ *
379
+ * With the `.usage()` method you can override the usage text that is
380
+ * displayed at the top of the auto generated help. By default the command
381
+ * arguments are used. The usage is always prefixed with the command name.
382
+ *
383
+ * @example Set custom usage
384
+ *
385
+ * ```ts
386
+ * import { Command } from "https://deno.land/x/cliffy/command/mod.ts";
387
+ *
388
+ * await new Command()
389
+ * .name("script-runner")
390
+ * .description("Simple script runner.")
391
+ * .usage("[options] [script] [script options]")
392
+ * // ...
393
+ * .parse(Deno.args);
394
+ * ```
395
+ *
396
+ * @param usage The command usage.
397
+ */
398
+ usage(usage) {
399
+ this.cmd.settings.usage = usage;
400
+ return this;
401
+ }
402
+ /** Hide command from help, completions, etc. */
403
+ hidden() {
404
+ this.cmd.settings.isHidden = true;
405
+ return this;
406
+ }
407
+ /** Make command globally available. */
408
+ global() {
409
+ this.cmd.settings.isGlobal = true;
410
+ return this;
411
+ }
412
+ /**
413
+ * Set command arguments.
414
+ *
415
+ * You can use the {@linkcode Command.arguments} method to specify the
416
+ * arguments for the command.
417
+ *
418
+ * This method will override any previously defined arguments.
419
+ *
420
+ * Angled brackets (e.g. `<required>`) indicate required input and
421
+ * square brackets (e.g. `[optional]`) indicate optional input. A required
422
+ * input cannot be defined after an optional input.
423
+ *
424
+ * Arguments can be also defined with the {@linkcode Command.command} method.
425
+ *
426
+ * Optionally you can define [types](./types.md) and
427
+ * [completions](./shell_completions.md) for your arguments after the argument
428
+ * name separated by colon. If no type is specified the type defaults to
429
+ * `string`.
430
+ *
431
+ * @example Define arguments
432
+ *
433
+ * ```ts
434
+ * import { Command } from "@cliffy/command";
435
+ *
436
+ * const cmd = new Command()
437
+ * .name("example")
438
+ * .arguments("<input-file:string> [output-file:string] [...tags:string]", [
439
+ * "The input file.",
440
+ * "The output file.",
441
+ * "Tags for the file."
442
+ * ]);
443
+ *
444
+ * // Parsing arguments
445
+ * const { args } = await cmd.parse(["input.txt", "result.txt", "tag1", "tag2"]);
446
+ *
447
+ * console.log(args); // Output: ['input.txt', 'result.txt', 'tag1', 'tag2']
448
+ * ```
449
+ *
450
+ * @example Use custom types in arguments
451
+ *
452
+ * ```typescript
453
+ * import { Command, EnumType } from "@cliffy/command";
454
+ *
455
+ * await new Command()
456
+ * .type("color", new EnumType(["red", "blue"]))
457
+ * .arguments("<color:color>")
458
+ * .action((_, color: "red" | "blue") => {
459
+ * console.log("color:", color);
460
+ * })
461
+ * .parse(Deno.args);
462
+ * ```
463
+ *
464
+ * @example Variadic arguments
465
+ *
466
+ * The last argument of a command can be variadic. To make an argument
467
+ * variadic you can append or prepend `...` to the argument name (`<...NAME>`
468
+ * or `<NAME...>`).
469
+ *
470
+ * Required rest arguments `<...args>` requires at least one argument, optional
471
+ * rest args `[...args]` are completely optional.
472
+ *
473
+ * ```typescript
474
+ * import { Command } from "https://deno.land/x/cliffy/command/mod.ts";
475
+ *
476
+ * await new Command()
477
+ * .description("Remove directories.")
478
+ * .arguments("<dirs...>")
479
+ * .action((_, ...dirs: Array<string>) => {
480
+ * for (const dir of dirs) {
481
+ * console.log("rmdir %s", dir);
482
+ * }
483
+ * })
484
+ * .parse(Deno.args);
485
+ * ```
486
+ *
487
+ * ```console
488
+ * $ deno run example.ts dir1 dir2 dir3
489
+ * rmdir dir1
490
+ * rmdir dir2
491
+ * rmdir dir3
492
+ * ```
493
+ *
494
+ * @param args The arguments definition string.
495
+ * @param descriptions The argument descriptions.
496
+ * @returns The command instance.
497
+ */
498
+ arguments(args, descriptions) {
499
+ this.cmd.settings.arguments = args.split(" ").map((arg, index) => ({
500
+ arg,
501
+ description: descriptions?.[index],
502
+ }));
503
+ return this;
504
+ }
505
+ /**
506
+ * Add a new command argument.
507
+ *
508
+ * - When called multiple times, arguments are appended in the order of calls.
509
+ * - When called after `arguments()`, the new argument is appended after the previously
510
+ * defined arguments.
511
+ * - When called before `arguments()`, the new argument is overwritten by the later
512
+ * defined arguments.
513
+ *
514
+ * @example
515
+ * ```ts
516
+ * import { Command } from "@cliffy/command";
517
+ *
518
+ * const cmd = new Command()
519
+ * .name("example")
520
+ * .argument("<input-file:string>", "The input file.")
521
+ * .argument("[output-file:string]", "The output file.", { default: "out.txt" })
522
+ * .argument("[...tags:string]", "Tags for the file.");
523
+ *
524
+ * // Parsing arguments
525
+ * const { args } = await cmd.parse(["input.txt", "result.txt", "tag1", "tag2"]);
526
+ *
527
+ * console.log(args); // Output: ['input.txt', 'result.txt', 'tag1', 'tag2']
528
+ * ```
529
+ *
530
+ * @param arg The argument definition. E.g: `<input-file:string>`
531
+ * @param description The argument description.
532
+ * @param opts Argument options.
533
+ * @returns The command instance.
534
+ */
535
+ argument(arg, description, opts) {
536
+ this.cmd.settings.arguments ??= [];
537
+ this.cmd.settings.arguments.push({ arg, description, ...opts });
538
+ return this;
539
+ }
540
+ /**
541
+ * Set command callback method.
542
+ *
543
+ * @param fn Command action handler.
544
+ */
545
+ action(fn) {
546
+ this.cmd.settings.actionHandler = fn;
547
+ return this;
548
+ }
549
+ /**
550
+ * Set command callback method.
551
+ *
552
+ * @param fn Command action handler.
553
+ */
554
+ globalAction(fn) {
555
+ this.cmd.settings.globalActionHandler = fn;
556
+ return this;
557
+ }
558
+ /**
559
+ * Don't throw an error if the command was called without arguments.
560
+ *
561
+ * @param allowEmpty Enable/disable allow empty.
562
+ */
563
+ allowEmpty(allowEmpty) {
564
+ this.cmd.settings.allowEmpty = allowEmpty !== false;
565
+ return this;
566
+ }
567
+ /**
568
+ * Enable stop early. If enabled, all arguments starting from the first non
569
+ * option argument will be passed as arguments with type string to the command
570
+ * action handler.
571
+ *
572
+ * For example:
573
+ * `command --debug-level warning server --port 80`
574
+ *
575
+ * Will result in:
576
+ * - options: `{ debugLevel: 'warning' }`
577
+ * - args: `['server', '--port', '80']`
578
+ *
579
+ * @param stopEarly Enable/disable stop early.
580
+ */
581
+ stopEarly(stopEarly = true) {
582
+ this.cmd.settings.stopEarly = stopEarly;
583
+ return this;
584
+ }
585
+ /**
586
+ * Disable parsing arguments. If enabled the raw arguments will be passed to
587
+ * the action handler. This has no effect for parent or child commands. Only
588
+ * for the command on which this method was called.
589
+ *
590
+ * @param useRawArgs Enable/disable raw arguments.
591
+ */
592
+ useRawArgs(useRawArgs = true) {
593
+ this.cmd.settings.useRawArgs = useRawArgs;
594
+ return this;
595
+ }
596
+ /**
597
+ * Set default command.
598
+ *
599
+ * The default command is executed when the command was called without any
600
+ * additional arguments.
601
+ *
602
+ * @param name Name of the default command.
603
+ */
604
+ default(name) {
605
+ this.cmd.settings.defaultCommand = name;
606
+ return this;
607
+ }
608
+ globalType(name, handler, options) {
609
+ return this.type(name, handler, { ...options, global: true });
610
+ }
611
+ /**
612
+ * Register custom type.
613
+ *
614
+ * @param name The name of the type.
615
+ * @param handler The callback method to parse the type.
616
+ * @param options Type options.
617
+ */
618
+ type(name, handler, options) {
619
+ if (this.cmd.builder.types.get(name) && !options?.override) {
620
+ throw new DuplicateTypeError(name);
621
+ }
622
+ this.cmd.builder.types.set(name, {
623
+ ...options,
624
+ name,
625
+ handler: handler,
626
+ });
627
+ if (handler instanceof Type &&
628
+ (typeof handler.complete !== "undefined" ||
629
+ typeof handler.values !== "undefined")) {
630
+ const completeHandler = (cmd, parent) => handler.complete?.(cmd, parent) || [];
631
+ this.complete(name, completeHandler, options);
632
+ }
633
+ return this;
634
+ }
635
+ /**
636
+ * Register global complete handler.
637
+ *
638
+ * @param name The name of the completion.
639
+ * @param complete The callback method to complete the type.
640
+ * @param options Complete options.
641
+ */
642
+ globalComplete(name, complete, options) {
643
+ return this.complete(name, complete, { ...options, global: true });
644
+ }
645
+ complete(name, complete, options) {
646
+ if (this.cmd.builder.completions.has(name) && !options?.override) {
647
+ throw new DuplicateCompletionError(name);
648
+ }
649
+ this.cmd.builder.completions.set(name, {
650
+ name,
651
+ complete,
652
+ ...options,
653
+ });
654
+ return this;
655
+ }
656
+ /**
657
+ * Throw validation errors instead of calling `exit()` to handle
658
+ * validation errors manually.
659
+ *
660
+ * A validation error is thrown when the command is wrongly used by the user.
661
+ * For example: If the user passes some invalid options or arguments to the
662
+ * command.
663
+ *
664
+ * This has no effect for parent commands. Only for the command on which this
665
+ * method was called and all child commands.
666
+ *
667
+ * **Example:**
668
+ *
669
+ * ```ts
670
+ * import { Command, ValidationError } from "./mod.ts";
671
+ *
672
+ * const cmd = new Command();
673
+ * // ...
674
+ *
675
+ * try {
676
+ * cmd.parse();
677
+ * } catch(error) {
678
+ * if (error instanceof ValidationError) {
679
+ * cmd.showHelp();
680
+ * Deno.exit(1);
681
+ * }
682
+ * throw error;
683
+ * }
684
+ * ```
685
+ *
686
+ * @see ValidationError
687
+ */
688
+ throwErrors() {
689
+ this.cmd.settings.throwOnError = true;
690
+ return this;
691
+ }
692
+ /**
693
+ * Set custom error handler.
694
+ *
695
+ * @param handler Error handler callback function.
696
+ */
697
+ error(handler) {
698
+ this.cmd.settings.errorHandler = handler;
699
+ return this;
700
+ }
701
+ /** Get error handler callback function. */
702
+ getErrorHandler() {
703
+ return this.settings.errorHandler ??
704
+ (this.parent && this.parent.settings.errorHandler);
705
+ }
706
+ /**
707
+ * Same as `.throwErrors()` but also prevents calling `exit()` after
708
+ * printing help or version with the --help and --version option.
709
+ */
710
+ noExit() {
711
+ this.cmd.settings.shouldExit = false;
712
+ this.throwErrors();
713
+ return this;
714
+ }
715
+ /**
716
+ * Disable inheriting global commands, options and environment variables from
717
+ * parent commands.
718
+ */
719
+ noGlobals() {
720
+ this.cmd.settings.noGlobals = true;
721
+ return this;
722
+ }
723
+ /** Check whether the command should throw errors or exit. */
724
+ shouldThrowErrors() {
725
+ return this.settings.throwOnError || !!this.parent?.shouldThrowErrors();
726
+ }
727
+ /** Check whether the command should exit after printing help or version. */
728
+ shouldExit() {
729
+ return this.settings.shouldExit ?? this.parent?.shouldExit() ?? true;
730
+ }
731
+ /**
732
+ * Enable grouping of options and set the name of the group.
733
+ * All option which are added after calling the `.group()` method will be
734
+ * grouped in the help output. If the `.group()` method can be use multiple
735
+ * times to create more groups.
736
+ *
737
+ * @param name The name of the option group.
738
+ */
739
+ group(name) {
740
+ this.cmd.builder.groupName = name;
741
+ return this;
742
+ }
743
+ /**
744
+ * Register a global option.
745
+ *
746
+ * @param flags Flags string e.g: -h, --help, --manual <requiredArg:string> [optionalArg:number] [...restArgs:string]
747
+ * @param desc Flag description.
748
+ * @param opts Flag options or custom handler for processing flag value.
749
+ */
750
+ globalOption(flags, desc, opts) {
751
+ if (typeof opts === "function") {
752
+ return this.option(flags, desc, { value: opts, global: true });
753
+ }
754
+ return this.option(flags, desc, { ...opts, global: true });
755
+ }
756
+ option(flags, desc, opts) {
757
+ if (typeof opts === "function") {
758
+ opts = { value: opts };
759
+ }
760
+ const result = splitArguments(flags);
761
+ const args = result.typeDefinition
762
+ ? parseArgumentsDefinition(result.typeDefinition)
763
+ : [];
764
+ const option = {
765
+ ...opts,
766
+ name: "",
767
+ description: desc,
768
+ args,
769
+ flags: result.flags,
770
+ equalsSign: result.equalsSign,
771
+ typeDefinition: result.typeDefinition,
772
+ groupName: this.builder.groupName ?? undefined,
773
+ };
774
+ if (option.separator) {
775
+ for (const arg of args) {
776
+ if (arg.list) {
777
+ arg.separator = option.separator;
778
+ }
779
+ }
780
+ }
781
+ for (const part of option.flags) {
782
+ const arg = part.trim();
783
+ const isLong = /^--/.test(arg);
784
+ const name = isLong ? arg.slice(2) : arg.slice(1);
785
+ if (this.cmd.getBaseOption(name, true)) {
786
+ if (opts?.override) {
787
+ this.removeOption(name);
788
+ }
789
+ else {
790
+ throw new DuplicateOptionNameError(name, this.getPath());
791
+ }
792
+ }
793
+ if (!option.name && isLong) {
794
+ option.name = name;
795
+ }
796
+ else if (!option.aliases) {
797
+ option.aliases = [name];
798
+ }
799
+ else {
800
+ option.aliases.push(name);
801
+ }
802
+ }
803
+ if (option.prepend) {
804
+ this.cmd.builder.options.unshift(option);
805
+ }
806
+ else {
807
+ this.cmd.builder.options.push(option);
808
+ }
809
+ return this;
810
+ }
811
+ /**
812
+ * Register command example.
813
+ *
814
+ * @param name Name of the example.
815
+ * @param description The content of the example.
816
+ */
817
+ example(name, description) {
818
+ if (this.cmd.hasExample(name)) {
819
+ throw new DuplicateExampleError(name);
820
+ }
821
+ this.cmd.settings.examples.push({ name, description });
822
+ return this;
823
+ }
824
+ /**
825
+ * @param flags Flags string e.g: -h, --help, --manual <requiredArg:string> [optionalArg:number] [...restArgs:string]
826
+ * @param desc Flag description.
827
+ * @param opts Flag options or custom handler for processing flag value.
828
+ */
829
+ /**
830
+ * Register a global environment variable.
831
+ *
832
+ * @param name Name of the environment variable.
833
+ * @param description The description of the environment variable.
834
+ * @param options Environment variable options.
835
+ */
836
+ globalEnv(name, description, options) {
837
+ return this.env(name, description, { ...options, global: true });
838
+ }
839
+ env(name, description, options) {
840
+ const result = splitArguments(name);
841
+ if (!result.typeDefinition) {
842
+ result.typeDefinition = "<value:boolean>";
843
+ }
844
+ if (result.flags.some((envName) => this.cmd.getBaseEnvVar(envName, true))) {
845
+ throw new DuplicateEnvVarError(name);
846
+ }
847
+ const details = parseArgumentsDefinition(result.typeDefinition);
848
+ if (details.length > 1) {
849
+ throw new TooManyEnvVarValuesError(name);
850
+ }
851
+ else if (details.length && details[0].optional) {
852
+ throw new UnexpectedOptionalEnvVarValueError(name);
853
+ }
854
+ else if (details.length && details[0].variadic) {
855
+ throw new UnexpectedVariadicEnvVarValueError(name);
856
+ }
857
+ this.cmd.builder.envVars.push({
858
+ name: result.flags[0],
859
+ names: result.flags,
860
+ description,
861
+ type: details[0].type,
862
+ details: details.shift(),
863
+ ...options,
864
+ });
865
+ return this;
866
+ }
867
+ /*****************************************************************************
868
+ **** MAIN HANDLER ***********************************************************
869
+ *****************************************************************************/
870
+ /**
871
+ * Parse command line arguments and execute matched command.
872
+ *
873
+ * @param args Command line args to parse. Ex: `cmd.parse( Deno.args )`
874
+ */
875
+ parse(args = getArgs()) {
876
+ this.props.isRoot = true;
877
+ const ctx = {
878
+ unknown: args.slice(),
879
+ flags: {},
880
+ env: {},
881
+ literal: [],
882
+ stopEarly: false,
883
+ stopOnUnknown: false,
884
+ defaults: {},
885
+ actions: [],
886
+ parsedFlags: [],
887
+ };
888
+ return this.parseCommand(ctx);
889
+ }
890
+ async parseCommand(ctx) {
891
+ try {
892
+ this.reset();
893
+ this.registerDefaults();
894
+ this.props.rawArgs = ctx.unknown.slice();
895
+ if (this.settings.defaultCommand && !ctx.parsedFlags.length &&
896
+ !ctx.unknown.length) {
897
+ const defaultCommand = this.getCommand(this.settings.defaultCommand, true);
898
+ if (!defaultCommand) {
899
+ throw new DefaultCommandNotFoundError(this.settings.defaultCommand, this.getCommands());
900
+ }
901
+ defaultCommand.props.globalParent = this;
902
+ return defaultCommand.parseCommand(ctx);
903
+ }
904
+ if (this.settings.useRawArgs) {
905
+ await this.parseEnvVars(ctx, this.builder.envVars);
906
+ return await this.execute(ctx.env, ctx.unknown, ctx);
907
+ }
908
+ let preParseGlobals = false;
909
+ let subCommand;
910
+ // Pre parse globals to support: cmd --global-option sub-command --option
911
+ if (ctx.unknown.length > 0) {
912
+ // Detect sub command.
913
+ subCommand = this.getSubCommand(ctx);
914
+ if (!subCommand) {
915
+ // Only pre parse globals if first arg ist a global option.
916
+ const optionName = ctx.unknown[0].replace(/^-+/, "").split("=")[0];
917
+ const option = this.getOption(optionName, true);
918
+ if (option?.global && !option.standalone) {
919
+ preParseGlobals = true;
920
+ await this.parseGlobalOptionsAndEnvVars(ctx);
921
+ }
922
+ }
923
+ }
924
+ if (subCommand || ctx.unknown.length > 0) {
925
+ subCommand ??= this.getSubCommand(ctx);
926
+ if (subCommand) {
927
+ subCommand.props.globalParent = this;
928
+ return subCommand.parseCommand(ctx);
929
+ }
930
+ }
931
+ // Parse rest options & env vars.
932
+ await this.parseOptionsAndEnvVars(ctx, preParseGlobals);
933
+ const options = { ...ctx.env, ...ctx.flags };
934
+ this.props.parsedOptions = options;
935
+ // Process arguments.
936
+ await this.processArguments(ctx);
937
+ const args = ctx.args ?? [];
938
+ this.props.parsedArgs = args;
939
+ this.props.literalArgs = ctx.literal;
940
+ // Execute option action.
941
+ if (ctx.actions.length) {
942
+ await Promise.all(ctx.actions.map((action) => action.call(this, options, ...args)));
943
+ if (ctx.standalone) {
944
+ return {
945
+ options,
946
+ args,
947
+ cmd: this,
948
+ literal: this.props.literalArgs,
949
+ };
950
+ }
951
+ }
952
+ return await this.execute(options, args, ctx);
953
+ }
954
+ catch (error) {
955
+ this.handleError(error);
956
+ }
957
+ }
958
+ getSubCommand(ctx) {
959
+ const subCommand = this.getCommand(ctx.unknown[0], true);
960
+ if (subCommand) {
961
+ ctx.unknown.shift();
962
+ }
963
+ return subCommand;
964
+ }
965
+ async parseGlobalOptionsAndEnvVars(ctx) {
966
+ const isHelpOption = this.getHelpOption()?.flags.includes(ctx.unknown[0]);
967
+ // Parse global env vars.
968
+ const envVars = [
969
+ ...this.builder.envVars.filter((envVar) => envVar.global),
970
+ ...this.getGlobalEnvVars(true),
971
+ ];
972
+ await this.parseEnvVars(ctx, envVars, !isHelpOption);
973
+ // Parse global options.
974
+ const options = [
975
+ ...this.builder.options.filter((option) => option.global),
976
+ ...this.getGlobalOptions(true),
977
+ ];
978
+ this.parseOptions(ctx, options, {
979
+ stopEarly: true,
980
+ stopOnUnknown: true,
981
+ dotted: false,
982
+ });
983
+ }
984
+ async parseOptionsAndEnvVars(ctx, preParseGlobals) {
985
+ const helpOption = this.getHelpOption();
986
+ const isVersionOption = this.props.versionOption?.flags.includes(ctx.unknown[0]);
987
+ const isHelpOption = helpOption &&
988
+ (preParseGlobals
989
+ ? ctx.flags?.[helpOption.name] === true
990
+ : ctx.unknown.some((unknown) => helpOption.flags.includes(unknown)));
991
+ // Parse env vars.
992
+ const envVars = preParseGlobals
993
+ ? this.builder.envVars.filter((envVar) => !envVar.global)
994
+ : this.getEnvVars(true);
995
+ await this.parseEnvVars(ctx, envVars, !isHelpOption && !isVersionOption);
996
+ // Parse options.
997
+ const options = this.getOptions(true);
998
+ this.parseOptions(ctx, options, {
999
+ args: this.getArguments(),
1000
+ });
1001
+ }
1002
+ /** Register default options like `--version` and `--help`. */
1003
+ registerDefaults() {
1004
+ if (this.props.hasDefaults) {
1005
+ return this;
1006
+ }
1007
+ if (this.parent) {
1008
+ if (this.props.isRoot) {
1009
+ this.getMainCommand().registerDefaults();
1010
+ }
1011
+ return this;
1012
+ }
1013
+ this.props.hasDefaults = true;
1014
+ this.reset();
1015
+ !this.builder.types.has("string") &&
1016
+ this.type("string", new StringType(), { global: true });
1017
+ !this.builder.types.has("number") &&
1018
+ this.type("number", new NumberType(), { global: true });
1019
+ !this.builder.types.has("integer") &&
1020
+ this.type("integer", new IntegerType(), { global: true });
1021
+ !this.builder.types.has("boolean") &&
1022
+ this.type("boolean", new BooleanType(), { global: true });
1023
+ !this.builder.types.has("file") &&
1024
+ this.type("file", new FileType(), { global: true });
1025
+ !this.builder.types.has("secret") &&
1026
+ this.type("secret", new SecretType(), { global: true });
1027
+ if (!this.settings.help) {
1028
+ this.help({});
1029
+ }
1030
+ if (this.settings.versionOptions !== false &&
1031
+ (this.settings.versionOptions || this.settings.version)) {
1032
+ this.option(this.settings.versionOptions?.flags || "-V, --version", this.settings.versionOptions?.desc ||
1033
+ "Show the version number for this program.", {
1034
+ standalone: true,
1035
+ prepend: true,
1036
+ action: async function () {
1037
+ const long = this.getRawArgs().includes(`--${this.props.versionOption?.name}`);
1038
+ if (long) {
1039
+ await checkVersion(this);
1040
+ this.showLongVersion();
1041
+ }
1042
+ else {
1043
+ this.showVersion();
1044
+ }
1045
+ this.exit();
1046
+ },
1047
+ ...(this.settings.versionOptions?.opts ?? {}),
1048
+ });
1049
+ this.props.versionOption = this.builder.options[0];
1050
+ }
1051
+ if (this.settings.helpOptions !== false) {
1052
+ this.option(this.settings.helpOptions?.flags || "-h, --help", this.settings.helpOptions?.desc || "Show this help.", {
1053
+ standalone: true,
1054
+ global: true,
1055
+ prepend: true,
1056
+ action: async function () {
1057
+ const long = this.getRawArgs().includes(`--${this.getHelpOption()?.name}`);
1058
+ await checkVersion(this);
1059
+ this.showHelp({ long });
1060
+ this.exit();
1061
+ },
1062
+ ...(this.settings.helpOptions?.opts ?? {}),
1063
+ });
1064
+ this.props.helpOption = this.builder.options[0];
1065
+ }
1066
+ return this;
1067
+ }
1068
+ /**
1069
+ * Execute command.
1070
+ * @param options A map of all options and environment variables. This also
1071
+ * includes global options and environment variables. The options are parsed
1072
+ * and processed by the command before passed to the action handler.
1073
+ * @param args Positional arguments array.
1074
+ * @param ctx Parse context.
1075
+ */
1076
+ async execute(options, args, ctx) {
1077
+ // Show help if auto help is enabled, the command has sub commands, was
1078
+ // called without any arguments or options and has no action handler.
1079
+ if (this.settings.commands.size && !ctx.unknown.length &&
1080
+ !ctx.parsedFlags.length && !this.settings.actionHandler &&
1081
+ this.isAutoHelpEnabled()) {
1082
+ this.showHelp();
1083
+ this.exit();
1084
+ }
1085
+ await this.executeGlobalAction(options, args);
1086
+ await this.settings.actionHandler?.call(this, options, ...args);
1087
+ return {
1088
+ options,
1089
+ args,
1090
+ cmd: this,
1091
+ literal: this.props.literalArgs,
1092
+ };
1093
+ }
1094
+ async executeGlobalAction(options, args) {
1095
+ if (!this.settings.noGlobals) {
1096
+ await this.parent?.executeGlobalAction(options, args);
1097
+ }
1098
+ await this.settings.globalActionHandler?.call(this, options, ...args);
1099
+ }
1100
+ /** Parse raw command line arguments. */
1101
+ parseOptions(ctx, options, { stopEarly = this.settings.stopEarly, stopOnUnknown = false, dotted = true, args = [], } = {}) {
1102
+ parseFlags(ctx, {
1103
+ stopEarly,
1104
+ stopOnUnknown,
1105
+ dotted,
1106
+ allowEmpty: this.settings.allowEmpty,
1107
+ flags: options,
1108
+ args,
1109
+ ignoreDefaults: ctx.env,
1110
+ parse: (type) => this.parseType(type),
1111
+ option: (option) => {
1112
+ if (option.action) {
1113
+ ctx.actions.push(option.action);
1114
+ }
1115
+ },
1116
+ });
1117
+ }
1118
+ /** Parse argument type. */
1119
+ parseType(type) {
1120
+ const typeSettings = this.getType(type.type);
1121
+ if (!typeSettings) {
1122
+ throw new UnknownTypeError(type.type, this.getTypes().map((type) => type.name));
1123
+ }
1124
+ return typeSettings.handler instanceof Type
1125
+ ? typeSettings.handler.parse(type)
1126
+ : typeSettings.handler(type);
1127
+ }
1128
+ /**
1129
+ * Read and validate environment variables.
1130
+ * @param ctx Parse context.
1131
+ * @param envVars env vars defined by the command.
1132
+ * @param validate when true, throws an error if a required env var is missing.
1133
+ */
1134
+ async parseEnvVars(ctx, envVars, validate = true) {
1135
+ await Promise.all(envVars.map(async (envVar) => {
1136
+ const env = await this.findEnvVar(envVar.names);
1137
+ if (env) {
1138
+ const parseType = (value) => {
1139
+ return this.parseType({
1140
+ label: "Environment variable",
1141
+ type: envVar.type,
1142
+ name: env.name,
1143
+ value,
1144
+ });
1145
+ };
1146
+ const propertyName = underscoreToCamelCase(envVar.prefix
1147
+ ? envVar.names[0].replace(new RegExp(`^${envVar.prefix}`), "")
1148
+ : envVar.names[0]);
1149
+ if (envVar.details.list) {
1150
+ ctx.env[propertyName] = env.value
1151
+ .split(envVar.details.separator ?? ",")
1152
+ .map(parseType);
1153
+ }
1154
+ else {
1155
+ ctx.env[propertyName] = parseType(env.value);
1156
+ }
1157
+ if (envVar.value && typeof ctx.env[propertyName] !== "undefined") {
1158
+ ctx.env[propertyName] = envVar.value(ctx.env[propertyName]);
1159
+ }
1160
+ }
1161
+ else if (envVar.required && validate) {
1162
+ throw new MissingRequiredEnvVarError(envVar);
1163
+ }
1164
+ }));
1165
+ }
1166
+ async findEnvVar(names) {
1167
+ const statuses = await Promise.all(names.map(async (name) => {
1168
+ // dnt-shim-ignore
1169
+ const status = await globalThis.Deno?.permissions
1170
+ .query({ name: "env", variable: name });
1171
+ return { name, status };
1172
+ }));
1173
+ for (const { name, status } of statuses) {
1174
+ if (!status || status.state === "granted") {
1175
+ const value = getEnv(name);
1176
+ if (value) {
1177
+ return { name, value };
1178
+ }
1179
+ }
1180
+ }
1181
+ return undefined;
1182
+ }
1183
+ /**
1184
+ * Processes command-line arguments.
1185
+ *
1186
+ * @param ctx Parse context.
1187
+ */
1188
+ async processArguments(ctx) {
1189
+ if (!this.hasArguments() && ctx.unknown.length) {
1190
+ if (this.hasCommands(true)) {
1191
+ if (this.hasCommand(ctx.unknown[0], true)) {
1192
+ // e.g: command --global-foo --foo sub-command
1193
+ throw new TooManyArgumentsError(ctx.unknown);
1194
+ }
1195
+ else {
1196
+ throw new UnknownCommandError(ctx.unknown[0], this.getCommands());
1197
+ }
1198
+ }
1199
+ else {
1200
+ throw new NoArgumentsAllowedError(this.getPath());
1201
+ }
1202
+ }
1203
+ if (ctx.args?.length) {
1204
+ ctx.args = await Promise.all(ctx.args ?? []);
1205
+ }
1206
+ else if (ctx.stopEarly || ctx.stopOnUnknown) {
1207
+ ctx.args = ctx.unknown;
1208
+ }
1209
+ }
1210
+ handleError(error) {
1211
+ this.throw(error instanceof FlagsValidationError
1212
+ ? new ValidationError(error.message, { cause: error })
1213
+ : error instanceof Error
1214
+ ? error
1215
+ : new Error(`[non-error-thrown] ${error}`));
1216
+ }
1217
+ /**
1218
+ * Handle error. If `throwErrors` is enabled the error will be thrown,
1219
+ * otherwise a formatted error message will be printed and `exit(1)`
1220
+ * will be called. This will also trigger registered error handlers.
1221
+ *
1222
+ * @param error The error to handle.
1223
+ */
1224
+ throw(error) {
1225
+ if (error instanceof ValidationError) {
1226
+ error.cmd = this;
1227
+ }
1228
+ this.getErrorHandler()?.(error, this, {
1229
+ options: this.props.parsedOptions ?? {},
1230
+ args: this.props.parsedArgs ?? [],
1231
+ });
1232
+ if (this.shouldThrowErrors() || !(error instanceof ValidationError)) {
1233
+ throw error;
1234
+ }
1235
+ this.showHelp();
1236
+ console.error(red(` ${bold("error")}: ${error.message}\n`));
1237
+ exit(error instanceof ValidationError ? error.exitCode : 1);
1238
+ }
1239
+ /*****************************************************************************
1240
+ **** GETTER *****************************************************************
1241
+ *****************************************************************************/
1242
+ /** Get command name. */
1243
+ getName() {
1244
+ return this.settings.name;
1245
+ }
1246
+ /** Get parent command. */
1247
+ getParent() {
1248
+ return this.parent;
1249
+ }
1250
+ /**
1251
+ * Get parent command from global executed command.
1252
+ * Be sure, to call this method only inside an action handler. Unless this or any child command was executed,
1253
+ * this method returns always undefined.
1254
+ */
1255
+ getGlobalParent() {
1256
+ return this.props.globalParent;
1257
+ }
1258
+ /** Get main command. */
1259
+ getMainCommand() {
1260
+ return this.parent?.getMainCommand() ?? this;
1261
+ }
1262
+ /** Get command name aliases. */
1263
+ getAliases() {
1264
+ return this.settings.aliases;
1265
+ }
1266
+ /**
1267
+ * Get full command path.
1268
+ *
1269
+ * @param name Override the main command name.
1270
+ */
1271
+ getPath(name) {
1272
+ return this.parent && !this.props.isRoot
1273
+ ? this.parent.getPath(name) + " " + this.settings.name
1274
+ : name || this.settings.name;
1275
+ }
1276
+ /** Get arguments definition. E.g: <input-file:string> <output-file:string> */
1277
+ getArgsDefinition() {
1278
+ return this.settings.arguments?.map(({ arg }) => arg).join(" ");
1279
+ }
1280
+ /**
1281
+ * Get argument by name.
1282
+ *
1283
+ * @param name Name of the argument.
1284
+ */
1285
+ getArgument(name) {
1286
+ return this.getArguments().find((arg) => arg.name === name);
1287
+ }
1288
+ /** Get arguments. */
1289
+ getArguments() {
1290
+ if (!this.props.args.length && this.settings.arguments) {
1291
+ this.props.args = parseArgumentsDefinition(this.settings.arguments);
1292
+ }
1293
+ return this.props.args;
1294
+ }
1295
+ /** Check if command has arguments. */
1296
+ hasArguments() {
1297
+ return !!this.settings.arguments?.length;
1298
+ }
1299
+ /** Get command version. */
1300
+ getVersion() {
1301
+ return this.getVersionHandler()?.call(this, this);
1302
+ }
1303
+ /** Get help handler method. */
1304
+ getVersionHandler() {
1305
+ return this.settings.version ?? this.parent?.getVersionHandler();
1306
+ }
1307
+ /** Get command description. */
1308
+ getDescription() {
1309
+ // call description method only once
1310
+ return typeof this.settings.description === "function"
1311
+ ? this.settings.description = this.settings.description.call(this)
1312
+ : this.settings.description;
1313
+ }
1314
+ /** Get auto generated command usage. */
1315
+ getUsage() {
1316
+ return this.settings.usage ??
1317
+ [this.getArgsDefinition(), this.getRequiredOptionsDefinition()]
1318
+ .join(" ")
1319
+ .trim();
1320
+ }
1321
+ getRequiredOptionsDefinition() {
1322
+ return this.getOptions()
1323
+ .filter((option) => option.required)
1324
+ .map((option) => [findFlag(option.flags), option.typeDefinition].filter((v) => v)
1325
+ .join(" ")
1326
+ .trim())
1327
+ .join(" ");
1328
+ }
1329
+ /** Get short command description. This is the first line of the description. */
1330
+ getShortDescription() {
1331
+ return getDescription(this.getDescription(), true);
1332
+ }
1333
+ /** Get original command-line arguments. */
1334
+ getRawArgs() {
1335
+ return this.props.rawArgs;
1336
+ }
1337
+ /** Get all arguments defined after the double dash. */
1338
+ getLiteralArgs() {
1339
+ return this.props.literalArgs;
1340
+ }
1341
+ /** Output generated help without exiting. */
1342
+ showVersion() {
1343
+ console.log(this.getVersion());
1344
+ }
1345
+ /** Returns command name, version and meta data. */
1346
+ getLongVersion() {
1347
+ return `${bold(this.getMainCommand().getName())} ${brightBlue(this.getVersion() ?? "")}` +
1348
+ Object.entries(this.getMeta()).map(([k, v]) => `\n${bold(k)} ${brightBlue(v)}`).join("");
1349
+ }
1350
+ /** Outputs command name, version and meta data. */
1351
+ showLongVersion() {
1352
+ console.log(this.getLongVersion());
1353
+ }
1354
+ /** Output generated help without exiting. */
1355
+ showHelp(options) {
1356
+ console.log(this.getHelp(options));
1357
+ }
1358
+ /** Get generated help. */
1359
+ getHelp(options) {
1360
+ this.registerDefaults();
1361
+ return this.getHelpHandler().call(this, this, options ?? {});
1362
+ }
1363
+ /** Get help handler method. */
1364
+ getHelpHandler() {
1365
+ return this.settings.help ?? this.parent?.getHelpHandler();
1366
+ }
1367
+ exit(code = 0) {
1368
+ if (this.shouldExit()) {
1369
+ exit(code);
1370
+ }
1371
+ }
1372
+ /*****************************************************************************
1373
+ **** Options GETTER *********************************************************
1374
+ *****************************************************************************/
1375
+ /**
1376
+ * Checks whether the command has options or not.
1377
+ *
1378
+ * @param hidden Include hidden options.
1379
+ */
1380
+ hasOptions(hidden) {
1381
+ return this.getOptions(hidden).length > 0;
1382
+ }
1383
+ /**
1384
+ * Get options.
1385
+ *
1386
+ * @param hidden Include hidden options.
1387
+ */
1388
+ getOptions(hidden) {
1389
+ return this.getGlobalOptions(hidden).concat(this.getBaseOptions(hidden));
1390
+ }
1391
+ /**
1392
+ * Get base options.
1393
+ *
1394
+ * @param hidden Include hidden options.
1395
+ */
1396
+ getBaseOptions(hidden) {
1397
+ if (!this.builder.options.length) {
1398
+ return [];
1399
+ }
1400
+ return hidden
1401
+ ? this.builder.options.slice(0)
1402
+ : this.builder.options.filter((opt) => !opt.hidden);
1403
+ }
1404
+ /**
1405
+ * Get global options.
1406
+ *
1407
+ * @param hidden Include hidden options.
1408
+ */
1409
+ getGlobalOptions(hidden) {
1410
+ const helpOption = this.getHelpOption();
1411
+ const getGlobals = (cmd, noGlobals, options = [], names = []) => {
1412
+ if (cmd.builder.options.length) {
1413
+ for (const option of cmd.builder.options) {
1414
+ if (option.global &&
1415
+ !this.builder.options.find((opt) => opt.name === option.name) &&
1416
+ names.indexOf(option.name) === -1 &&
1417
+ (hidden || !option.hidden)) {
1418
+ if (noGlobals && option !== helpOption) {
1419
+ continue;
1420
+ }
1421
+ names.push(option.name);
1422
+ options.push(option);
1423
+ }
1424
+ }
1425
+ }
1426
+ return cmd.parent
1427
+ ? getGlobals(cmd.parent, noGlobals || cmd.settings.noGlobals, options, names)
1428
+ : options;
1429
+ };
1430
+ return this.parent ? getGlobals(this.parent, this.settings.noGlobals) : [];
1431
+ }
1432
+ /**
1433
+ * Checks whether the command has an option with given name or not.
1434
+ *
1435
+ * @param name Name of the option. Must be in param-case.
1436
+ * @param hidden Include hidden options.
1437
+ */
1438
+ hasOption(name, hidden) {
1439
+ return !!this.getOption(name, hidden);
1440
+ }
1441
+ /**
1442
+ * Get option by name.
1443
+ *
1444
+ * @param name Name of the option. Must be in param-case.
1445
+ * @param hidden Include hidden options.
1446
+ */
1447
+ getOption(name, hidden) {
1448
+ return this.getBaseOption(name, hidden) ??
1449
+ this.getGlobalOption(name, hidden);
1450
+ }
1451
+ /**
1452
+ * Get base option by name.
1453
+ *
1454
+ * @param name Name of the option. Must be in param-case.
1455
+ * @param hidden Include hidden options.
1456
+ */
1457
+ getBaseOption(name, hidden) {
1458
+ const option = this.builder.options.find((option) => option.name === name || option.aliases?.includes(name));
1459
+ return option && (hidden || !option.hidden) ? option : undefined;
1460
+ }
1461
+ /**
1462
+ * Get global option from parent commands by name.
1463
+ *
1464
+ * @param name Name of the option. Must be in param-case.
1465
+ * @param hidden Include hidden options.
1466
+ */
1467
+ getGlobalOption(name, hidden) {
1468
+ const helpOption = this.getHelpOption();
1469
+ const getGlobalOption = (parent, noGlobals) => {
1470
+ const option = parent.getBaseOption(name, hidden);
1471
+ if (!option?.global) {
1472
+ return parent.parent && getGlobalOption(parent.parent, noGlobals || parent.settings.noGlobals);
1473
+ }
1474
+ if (noGlobals && option !== helpOption) {
1475
+ return;
1476
+ }
1477
+ return option;
1478
+ };
1479
+ return this.parent && getGlobalOption(this.parent, this.settings.noGlobals);
1480
+ }
1481
+ /**
1482
+ * Remove option by name.
1483
+ *
1484
+ * @param name Name of the option. Must be in param-case.
1485
+ */
1486
+ removeOption(name) {
1487
+ const index = this.builder.options.findIndex((option) => option.name === name);
1488
+ if (index === -1) {
1489
+ return;
1490
+ }
1491
+ return this.builder.options.splice(index, 1)[0];
1492
+ }
1493
+ /**
1494
+ * Checks whether the command has sub-commands or not.
1495
+ *
1496
+ * @param hidden Include hidden commands.
1497
+ */
1498
+ hasCommands(hidden) {
1499
+ return this.getCommands(hidden).length > 0;
1500
+ }
1501
+ /**
1502
+ * Get commands.
1503
+ *
1504
+ * @param hidden Include hidden commands.
1505
+ */
1506
+ getCommands(hidden) {
1507
+ return this.getGlobalCommands(hidden).concat(this.getBaseCommands(hidden));
1508
+ }
1509
+ /**
1510
+ * Get base commands.
1511
+ *
1512
+ * @param hidden Include hidden commands.
1513
+ */
1514
+ getBaseCommands(hidden) {
1515
+ const commands = Array.from(this.settings.commands.values());
1516
+ return hidden ? commands : commands.filter((cmd) => !cmd.settings.isHidden);
1517
+ }
1518
+ /**
1519
+ * Get global commands.
1520
+ *
1521
+ * @param hidden Include hidden commands.
1522
+ */
1523
+ getGlobalCommands(hidden) {
1524
+ const getCommands = (command, noGlobals, commands = [], names = []) => {
1525
+ if (command.settings.commands.size) {
1526
+ for (const [_, cmd] of command.settings.commands) {
1527
+ if (cmd.settings.isGlobal &&
1528
+ this !== cmd &&
1529
+ !this.settings.commands.has(cmd.settings.name) &&
1530
+ names.indexOf(cmd.settings.name) === -1 &&
1531
+ (hidden || !cmd.settings.isHidden)) {
1532
+ if (noGlobals && cmd?.getName() !== "help") {
1533
+ continue;
1534
+ }
1535
+ names.push(cmd.settings.name);
1536
+ commands.push(cmd);
1537
+ }
1538
+ }
1539
+ }
1540
+ return command.parent
1541
+ ? getCommands(command.parent, noGlobals || command.settings.noGlobals, commands, names)
1542
+ : commands;
1543
+ };
1544
+ return this.parent ? getCommands(this.parent, this.settings.noGlobals) : [];
1545
+ }
1546
+ /**
1547
+ * Checks whether a child command exists by given name or alias.
1548
+ *
1549
+ * @param name Name or alias of the command.
1550
+ * @param hidden Include hidden commands.
1551
+ */
1552
+ hasCommand(name, hidden) {
1553
+ return !!this.getCommand(name, hidden);
1554
+ }
1555
+ /**
1556
+ * Get command by name or alias.
1557
+ *
1558
+ * @param name Name or alias of the command.
1559
+ * @param hidden Include hidden commands.
1560
+ */
1561
+ getCommand(name, hidden) {
1562
+ return this.getBaseCommand(name, hidden) ??
1563
+ this.getGlobalCommand(name, hidden);
1564
+ }
1565
+ /**
1566
+ * Get base command by name or alias.
1567
+ *
1568
+ * @param name Name or alias of the command.
1569
+ * @param hidden Include hidden commands.
1570
+ */
1571
+ getBaseCommand(name, hidden) {
1572
+ for (const cmd of this.settings.commands.values()) {
1573
+ if (cmd.settings.name === name || cmd.settings.aliases.includes(name)) {
1574
+ return (cmd && (hidden || !cmd.settings.isHidden) ? cmd : undefined);
1575
+ }
1576
+ }
1577
+ }
1578
+ /**
1579
+ * Get global command by name or alias.
1580
+ *
1581
+ * @param name Name or alias of the command.
1582
+ * @param hidden Include hidden commands.
1583
+ */
1584
+ getGlobalCommand(name, hidden) {
1585
+ const getGlobalCommand = (parent, noGlobals) => {
1586
+ const cmd = parent.getBaseCommand(name, hidden);
1587
+ if (!cmd || !cmd.settings.isGlobal) {
1588
+ return parent.parent &&
1589
+ getGlobalCommand(parent.parent, noGlobals || parent.settings.noGlobals);
1590
+ }
1591
+ if (noGlobals && cmd.getName() !== "help") {
1592
+ return;
1593
+ }
1594
+ return cmd;
1595
+ };
1596
+ return this.parent &&
1597
+ getGlobalCommand(this.parent, this.settings.noGlobals);
1598
+ }
1599
+ /**
1600
+ * Remove sub-command by name or alias.
1601
+ *
1602
+ * @param name Name or alias of the command.
1603
+ */
1604
+ removeCommand(name) {
1605
+ const command = this.getBaseCommand(name, true);
1606
+ if (command) {
1607
+ this.settings.commands.delete(command.settings.name);
1608
+ }
1609
+ return command;
1610
+ }
1611
+ /** Get types. */
1612
+ getTypes() {
1613
+ return this.getGlobalTypes().concat(this.getBaseTypes());
1614
+ }
1615
+ /** Get base types. */
1616
+ getBaseTypes() {
1617
+ return Array.from(this.builder.types.values());
1618
+ }
1619
+ /** Get global types. */
1620
+ getGlobalTypes() {
1621
+ const getTypes = (cmd, types = [], names = []) => {
1622
+ if (cmd) {
1623
+ if (cmd.builder.types.size) {
1624
+ cmd.builder.types.forEach((type) => {
1625
+ if (type.global &&
1626
+ !this.builder.types.has(type.name) &&
1627
+ names.indexOf(type.name) === -1) {
1628
+ names.push(type.name);
1629
+ types.push(type);
1630
+ }
1631
+ });
1632
+ }
1633
+ return getTypes(cmd.parent, types, names);
1634
+ }
1635
+ return types;
1636
+ };
1637
+ return getTypes(this.parent);
1638
+ }
1639
+ /**
1640
+ * Get type by name.
1641
+ *
1642
+ * @param name Name of the type.
1643
+ */
1644
+ getType(name) {
1645
+ return this.getBaseType(name) ?? this.getGlobalType(name);
1646
+ }
1647
+ /**
1648
+ * Get base type by name.
1649
+ *
1650
+ * @param name Name of the type.
1651
+ */
1652
+ getBaseType(name) {
1653
+ return this.builder.types.get(name);
1654
+ }
1655
+ /**
1656
+ * Get global type by name.
1657
+ *
1658
+ * @param name Name of the type.
1659
+ */
1660
+ getGlobalType(name) {
1661
+ if (!this.parent) {
1662
+ return;
1663
+ }
1664
+ const cmd = this.parent.getBaseType(name);
1665
+ if (!cmd?.global) {
1666
+ return this.parent.getGlobalType(name);
1667
+ }
1668
+ return cmd;
1669
+ }
1670
+ /** Get completions. */
1671
+ getCompletions() {
1672
+ return this.getGlobalCompletions().concat(this.getBaseCompletions());
1673
+ }
1674
+ /** Get base completions. */
1675
+ getBaseCompletions() {
1676
+ return Array.from(this.builder.completions.values());
1677
+ }
1678
+ /** Get global completions. */
1679
+ getGlobalCompletions() {
1680
+ const getCompletions = (cmd, completions = [], names = []) => {
1681
+ if (cmd) {
1682
+ if (cmd.builder.completions.size) {
1683
+ cmd.builder.completions.forEach((completion) => {
1684
+ if (completion.global &&
1685
+ !this.builder.completions.has(completion.name) &&
1686
+ names.indexOf(completion.name) === -1) {
1687
+ names.push(completion.name);
1688
+ completions.push(completion);
1689
+ }
1690
+ });
1691
+ }
1692
+ return getCompletions(cmd.parent, completions, names);
1693
+ }
1694
+ return completions;
1695
+ };
1696
+ return getCompletions(this.parent);
1697
+ }
1698
+ /**
1699
+ * Get completion by name.
1700
+ *
1701
+ * @param name Name of the completion.
1702
+ */
1703
+ getCompletion(name) {
1704
+ return this.getBaseCompletion(name) ?? this.getGlobalCompletion(name);
1705
+ }
1706
+ /**
1707
+ * Get base completion by name.
1708
+ *
1709
+ * @param name Name of the completion.
1710
+ */
1711
+ getBaseCompletion(name) {
1712
+ return this.builder.completions.get(name);
1713
+ }
1714
+ /**
1715
+ * Get global completions by name.
1716
+ *
1717
+ * @param name Name of the completion.
1718
+ */
1719
+ getGlobalCompletion(name) {
1720
+ if (!this.parent) {
1721
+ return;
1722
+ }
1723
+ const completion = this.parent.getBaseCompletion(name);
1724
+ if (!completion?.global) {
1725
+ return this.parent.getGlobalCompletion(name);
1726
+ }
1727
+ return completion;
1728
+ }
1729
+ /**
1730
+ * Checks whether the command has environment variables or not.
1731
+ *
1732
+ * @param hidden Include hidden environment variable.
1733
+ */
1734
+ hasEnvVars(hidden) {
1735
+ return this.getEnvVars(hidden).length > 0;
1736
+ }
1737
+ /**
1738
+ * Get environment variables.
1739
+ *
1740
+ * @param hidden Include hidden environment variable.
1741
+ */
1742
+ getEnvVars(hidden) {
1743
+ return this.getGlobalEnvVars(hidden).concat(this.getBaseEnvVars(hidden));
1744
+ }
1745
+ /**
1746
+ * Get base environment variables.
1747
+ *
1748
+ * @param hidden Include hidden environment variable.
1749
+ */
1750
+ getBaseEnvVars(hidden) {
1751
+ if (!this.builder.envVars.length) {
1752
+ return [];
1753
+ }
1754
+ return hidden
1755
+ ? this.builder.envVars.slice(0)
1756
+ : this.builder.envVars.filter((env) => !env.hidden);
1757
+ }
1758
+ /**
1759
+ * Get global environment variables.
1760
+ *
1761
+ * @param hidden Include hidden environment variable.
1762
+ */
1763
+ getGlobalEnvVars(hidden) {
1764
+ if (this.settings.noGlobals) {
1765
+ return [];
1766
+ }
1767
+ const getEnvVars = (cmd, envVars = [], names = []) => {
1768
+ if (cmd) {
1769
+ if (cmd.builder.envVars.length) {
1770
+ cmd.builder.envVars.forEach((envVar) => {
1771
+ if (envVar.global &&
1772
+ !this.builder.envVars.find((env) => env.names[0] === envVar.names[0]) &&
1773
+ names.indexOf(envVar.names[0]) === -1 &&
1774
+ (hidden || !envVar.hidden)) {
1775
+ names.push(envVar.names[0]);
1776
+ envVars.push(envVar);
1777
+ }
1778
+ });
1779
+ }
1780
+ return getEnvVars(cmd.parent, envVars, names);
1781
+ }
1782
+ return envVars;
1783
+ };
1784
+ return getEnvVars(this.parent);
1785
+ }
1786
+ /**
1787
+ * Checks whether the command has an environment variable with given name or not.
1788
+ *
1789
+ * @param name Name of the environment variable.
1790
+ * @param hidden Include hidden environment variable.
1791
+ */
1792
+ hasEnvVar(name, hidden) {
1793
+ return !!this.getEnvVar(name, hidden);
1794
+ }
1795
+ /**
1796
+ * Get environment variable by name.
1797
+ *
1798
+ * @param name Name of the environment variable.
1799
+ * @param hidden Include hidden environment variable.
1800
+ */
1801
+ getEnvVar(name, hidden) {
1802
+ return this.getBaseEnvVar(name, hidden) ??
1803
+ this.getGlobalEnvVar(name, hidden);
1804
+ }
1805
+ /**
1806
+ * Get base environment variable by name.
1807
+ *
1808
+ * @param name Name of the environment variable.
1809
+ * @param hidden Include hidden environment variable.
1810
+ */
1811
+ getBaseEnvVar(name, hidden) {
1812
+ const envVar = this.builder.envVars.find((env) => env.names.indexOf(name) !== -1);
1813
+ return envVar && (hidden || !envVar.hidden) ? envVar : undefined;
1814
+ }
1815
+ /**
1816
+ * Get global environment variable by name.
1817
+ *
1818
+ * @param name Name of the environment variable.
1819
+ * @param hidden Include hidden environment variable.
1820
+ */
1821
+ getGlobalEnvVar(name, hidden) {
1822
+ if (!this.parent || this.settings.noGlobals) {
1823
+ return;
1824
+ }
1825
+ const envVar = this.parent.getBaseEnvVar(name, hidden);
1826
+ if (!envVar?.global) {
1827
+ return this.parent.getGlobalEnvVar(name, hidden);
1828
+ }
1829
+ return envVar;
1830
+ }
1831
+ /** Checks whether the command has examples or not. */
1832
+ hasExamples() {
1833
+ return this.settings.examples.length > 0;
1834
+ }
1835
+ /** Get all examples. */
1836
+ getExamples() {
1837
+ return this.settings.examples;
1838
+ }
1839
+ /** Checks whether the command has an example with given name or not. */
1840
+ hasExample(name) {
1841
+ return !!this.getExample(name);
1842
+ }
1843
+ /** Get example with given name. */
1844
+ getExample(name) {
1845
+ return this.settings.examples.find((example) => example.name === name);
1846
+ }
1847
+ getHelpOption() {
1848
+ return this.props.helpOption ?? this.parent?.getHelpOption();
1849
+ }
1850
+ isAutoHelpEnabled() {
1851
+ return this.settings.autoHelp ?? this.parent?.isAutoHelpEnabled() ?? true;
1852
+ }
1853
+ }
1854
+ function findFlag(flags) {
1855
+ for (const flag of flags) {
1856
+ if (flag.startsWith("--")) {
1857
+ return flag;
1858
+ }
1859
+ }
1860
+ return flags[0];
1861
+ }