@villedemontreal/caporal 3.1.7

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 (425) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/src/__tests__/issue-163.spec.d.ts +2 -0
  4. package/dist/src/__tests__/issue-163.spec.d.ts.map +1 -0
  5. package/dist/src/__tests__/issue-163.spec.js +17 -0
  6. package/dist/src/__tests__/issue-163.spec.js.map +1 -0
  7. package/dist/src/argument/__tests__/argument.spec.d.ts +2 -0
  8. package/dist/src/argument/__tests__/argument.spec.d.ts.map +1 -0
  9. package/dist/src/argument/__tests__/argument.spec.js +85 -0
  10. package/dist/src/argument/__tests__/argument.spec.js.map +1 -0
  11. package/dist/src/argument/find.d.ts +8 -0
  12. package/dist/src/argument/find.d.ts.map +1 -0
  13. package/dist/src/argument/find.js +11 -0
  14. package/dist/src/argument/find.js.map +1 -0
  15. package/dist/src/argument/index.d.ts +13 -0
  16. package/dist/src/argument/index.d.ts.map +1 -0
  17. package/dist/src/argument/index.js +27 -0
  18. package/dist/src/argument/index.js.map +1 -0
  19. package/dist/src/argument/synopsis.d.ts +19 -0
  20. package/dist/src/argument/synopsis.d.ts.map +1 -0
  21. package/dist/src/argument/synopsis.js +39 -0
  22. package/dist/src/argument/synopsis.js.map +1 -0
  23. package/dist/src/argument/validate.d.ts +43 -0
  24. package/dist/src/argument/validate.d.ts.map +1 -0
  25. package/dist/src/argument/validate.js +127 -0
  26. package/dist/src/argument/validate.js.map +1 -0
  27. package/dist/src/autocomplete/__fixtures__/prog-autocomplete.d.ts +3 -0
  28. package/dist/src/autocomplete/__fixtures__/prog-autocomplete.d.ts.map +1 -0
  29. package/dist/src/autocomplete/__fixtures__/prog-autocomplete.js +24 -0
  30. package/dist/src/autocomplete/__fixtures__/prog-autocomplete.js.map +1 -0
  31. package/dist/src/autocomplete/__tests__/autocomplete.spec.d.ts +2 -0
  32. package/dist/src/autocomplete/__tests__/autocomplete.spec.d.ts.map +1 -0
  33. package/dist/src/autocomplete/__tests__/autocomplete.spec.js +119 -0
  34. package/dist/src/autocomplete/__tests__/autocomplete.spec.js.map +1 -0
  35. package/dist/src/autocomplete/index.d.ts +20 -0
  36. package/dist/src/autocomplete/index.d.ts.map +1 -0
  37. package/dist/src/autocomplete/index.js +172 -0
  38. package/dist/src/autocomplete/index.js.map +1 -0
  39. package/dist/src/autocomplete/types.d.ts +26 -0
  40. package/dist/src/autocomplete/types.d.ts.map +1 -0
  41. package/dist/src/autocomplete/types.js +3 -0
  42. package/dist/src/autocomplete/types.js.map +1 -0
  43. package/dist/src/command/__fixtures__/example-cmd.d.ts +8 -0
  44. package/dist/src/command/__fixtures__/example-cmd.d.ts.map +1 -0
  45. package/dist/src/command/__fixtures__/example-cmd.js +10 -0
  46. package/dist/src/command/__fixtures__/example-cmd.js.map +1 -0
  47. package/dist/src/command/__tests__/command.spec.d.ts +2 -0
  48. package/dist/src/command/__tests__/command.spec.d.ts.map +1 -0
  49. package/dist/src/command/__tests__/command.spec.js +510 -0
  50. package/dist/src/command/__tests__/command.spec.js.map +1 -0
  51. package/dist/src/command/__tests__/find.spec.d.ts +2 -0
  52. package/dist/src/command/__tests__/find.spec.d.ts.map +1 -0
  53. package/dist/src/command/__tests__/find.spec.js +31 -0
  54. package/dist/src/command/__tests__/find.spec.js.map +1 -0
  55. package/dist/src/command/__tests__/import.spec.d.ts +2 -0
  56. package/dist/src/command/__tests__/import.spec.d.ts.map +1 -0
  57. package/dist/src/command/__tests__/import.spec.js +17 -0
  58. package/dist/src/command/__tests__/import.spec.js.map +1 -0
  59. package/dist/src/command/__tests__/scan.spec.d.ts +2 -0
  60. package/dist/src/command/__tests__/scan.spec.d.ts.map +1 -0
  61. package/dist/src/command/__tests__/scan.spec.js +20 -0
  62. package/dist/src/command/__tests__/scan.spec.js.map +1 -0
  63. package/dist/src/command/find.d.ts +8 -0
  64. package/dist/src/command/find.d.ts.map +1 -0
  65. package/dist/src/command/find.js +47 -0
  66. package/dist/src/command/find.js.map +1 -0
  67. package/dist/src/command/import.d.ts +7 -0
  68. package/dist/src/command/import.d.ts.map +1 -0
  69. package/dist/src/command/import.js +47 -0
  70. package/dist/src/command/import.js.map +1 -0
  71. package/dist/src/command/index.d.ts +211 -0
  72. package/dist/src/command/index.d.ts.map +1 -0
  73. package/dist/src/command/index.js +374 -0
  74. package/dist/src/command/index.js.map +1 -0
  75. package/dist/src/command/scan.d.ts +4 -0
  76. package/dist/src/command/scan.d.ts.map +1 -0
  77. package/dist/src/command/scan.js +31 -0
  78. package/dist/src/command/scan.js.map +1 -0
  79. package/dist/src/command/validate-call.d.ts +8 -0
  80. package/dist/src/command/validate-call.d.ts.map +1 -0
  81. package/dist/src/command/validate-call.js +13 -0
  82. package/dist/src/command/validate-call.js.map +1 -0
  83. package/dist/src/config/index.d.ts +7 -0
  84. package/dist/src/config/index.d.ts.map +1 -0
  85. package/dist/src/config/index.js +24 -0
  86. package/dist/src/config/index.js.map +1 -0
  87. package/dist/src/error/__tests__/fatal.spec.d.ts +2 -0
  88. package/dist/src/error/__tests__/fatal.spec.d.ts.map +1 -0
  89. package/dist/src/error/__tests__/fatal.spec.js +34 -0
  90. package/dist/src/error/__tests__/fatal.spec.js.map +1 -0
  91. package/dist/src/error/action.d.ts +9 -0
  92. package/dist/src/error/action.d.ts.map +1 -0
  93. package/dist/src/error/action.js +16 -0
  94. package/dist/src/error/action.js.map +1 -0
  95. package/dist/src/error/base.d.ts +11 -0
  96. package/dist/src/error/base.d.ts.map +1 -0
  97. package/dist/src/error/base.js +18 -0
  98. package/dist/src/error/base.js.map +1 -0
  99. package/dist/src/error/fatal.d.ts +10 -0
  100. package/dist/src/error/fatal.d.ts.map +1 -0
  101. package/dist/src/error/fatal.js +27 -0
  102. package/dist/src/error/fatal.js.map +1 -0
  103. package/dist/src/error/index.d.ts +18 -0
  104. package/dist/src/error/index.d.ts.map +1 -0
  105. package/dist/src/error/index.js +34 -0
  106. package/dist/src/error/index.js.map +1 -0
  107. package/dist/src/error/invalid-validator.d.ts +10 -0
  108. package/dist/src/error/invalid-validator.d.ts.map +1 -0
  109. package/dist/src/error/invalid-validator.js +15 -0
  110. package/dist/src/error/invalid-validator.js.map +1 -0
  111. package/dist/src/error/missing-argument.d.ts +11 -0
  112. package/dist/src/error/missing-argument.d.ts.map +1 -0
  113. package/dist/src/error/missing-argument.js +20 -0
  114. package/dist/src/error/missing-argument.js.map +1 -0
  115. package/dist/src/error/missing-flag.d.ts +11 -0
  116. package/dist/src/error/missing-flag.d.ts.map +1 -0
  117. package/dist/src/error/missing-flag.js +20 -0
  118. package/dist/src/error/missing-flag.js.map +1 -0
  119. package/dist/src/error/multi-validation.d.ts +10 -0
  120. package/dist/src/error/multi-validation.d.ts.map +1 -0
  121. package/dist/src/error/multi-validation.js +26 -0
  122. package/dist/src/error/multi-validation.js.map +1 -0
  123. package/dist/src/error/no-action.d.ts +10 -0
  124. package/dist/src/error/no-action.d.ts.map +1 -0
  125. package/dist/src/error/no-action.js +22 -0
  126. package/dist/src/error/no-action.js.map +1 -0
  127. package/dist/src/error/option-synopsis-syntax.d.ts +9 -0
  128. package/dist/src/error/option-synopsis-syntax.d.ts.map +1 -0
  129. package/dist/src/error/option-synopsis-syntax.js +15 -0
  130. package/dist/src/error/option-synopsis-syntax.js.map +1 -0
  131. package/dist/src/error/too-many-arguments.d.ts +11 -0
  132. package/dist/src/error/too-many-arguments.d.ts.map +1 -0
  133. package/dist/src/error/too-many-arguments.js +25 -0
  134. package/dist/src/error/too-many-arguments.js.map +1 -0
  135. package/dist/src/error/unknown-command.d.ts +13 -0
  136. package/dist/src/error/unknown-command.d.ts.map +1 -0
  137. package/dist/src/error/unknown-command.js +44 -0
  138. package/dist/src/error/unknown-command.js.map +1 -0
  139. package/dist/src/error/unknown-option.d.ts +13 -0
  140. package/dist/src/error/unknown-option.d.ts.map +1 -0
  141. package/dist/src/error/unknown-option.js +40 -0
  142. package/dist/src/error/unknown-option.js.map +1 -0
  143. package/dist/src/error/validation.d.ts +17 -0
  144. package/dist/src/error/validation.d.ts.map +1 -0
  145. package/dist/src/error/validation.js +49 -0
  146. package/dist/src/error/validation.js.map +1 -0
  147. package/dist/src/help/__tests__/help.spec.d.ts +2 -0
  148. package/dist/src/help/__tests__/help.spec.d.ts.map +1 -0
  149. package/dist/src/help/__tests__/help.spec.js +130 -0
  150. package/dist/src/help/__tests__/help.spec.js.map +1 -0
  151. package/dist/src/help/__tests__/utils.spec.d.ts +2 -0
  152. package/dist/src/help/__tests__/utils.spec.d.ts.map +1 -0
  153. package/dist/src/help/__tests__/utils.spec.js +16 -0
  154. package/dist/src/help/__tests__/utils.spec.js.map +1 -0
  155. package/dist/src/help/index.d.ts +47 -0
  156. package/dist/src/help/index.d.ts.map +1 -0
  157. package/dist/src/help/index.js +131 -0
  158. package/dist/src/help/index.js.map +1 -0
  159. package/dist/src/help/templates/command.d.ts +7 -0
  160. package/dist/src/help/templates/command.d.ts.map +1 -0
  161. package/dist/src/help/templates/command.js +23 -0
  162. package/dist/src/help/templates/command.js.map +1 -0
  163. package/dist/src/help/templates/custom.d.ts +7 -0
  164. package/dist/src/help/templates/custom.d.ts.map +1 -0
  165. package/dist/src/help/templates/custom.js +24 -0
  166. package/dist/src/help/templates/custom.js.map +1 -0
  167. package/dist/src/help/templates/header.d.ts +7 -0
  168. package/dist/src/help/templates/header.d.ts.map +1 -0
  169. package/dist/src/help/templates/header.js +16 -0
  170. package/dist/src/help/templates/header.js.map +1 -0
  171. package/dist/src/help/templates/index.d.ts +10 -0
  172. package/dist/src/help/templates/index.d.ts.map +1 -0
  173. package/dist/src/help/templates/index.js +26 -0
  174. package/dist/src/help/templates/index.js.map +1 -0
  175. package/dist/src/help/templates/program.d.ts +7 -0
  176. package/dist/src/help/templates/program.d.ts.map +1 -0
  177. package/dist/src/help/templates/program.js +18 -0
  178. package/dist/src/help/templates/program.js.map +1 -0
  179. package/dist/src/help/templates/usage.d.ts +7 -0
  180. package/dist/src/help/templates/usage.d.ts.map +1 -0
  181. package/dist/src/help/templates/usage.js +19 -0
  182. package/dist/src/help/templates/usage.js.map +1 -0
  183. package/dist/src/help/types.d.ts +53 -0
  184. package/dist/src/help/types.d.ts.map +1 -0
  185. package/dist/src/help/types.js +3 -0
  186. package/dist/src/help/types.js.map +1 -0
  187. package/dist/src/help/utils.d.ts +9 -0
  188. package/dist/src/help/utils.d.ts.map +1 -0
  189. package/dist/src/help/utils.js +92 -0
  190. package/dist/src/help/utils.js.map +1 -0
  191. package/dist/src/index.d.ts +90 -0
  192. package/dist/src/index.d.ts.map +1 -0
  193. package/dist/src/index.js +111 -0
  194. package/dist/src/index.js.map +1 -0
  195. package/dist/src/logger/__tests__/logger.spec.d.ts +2 -0
  196. package/dist/src/logger/__tests__/logger.spec.d.ts.map +1 -0
  197. package/dist/src/logger/__tests__/logger.spec.js +56 -0
  198. package/dist/src/logger/__tests__/logger.spec.js.map +1 -0
  199. package/dist/src/logger/index.d.ts +6 -0
  200. package/dist/src/logger/index.d.ts.map +1 -0
  201. package/dist/src/logger/index.js +128 -0
  202. package/dist/src/logger/index.js.map +1 -0
  203. package/dist/src/option/__tests__/global.spec.d.ts +2 -0
  204. package/dist/src/option/__tests__/global.spec.d.ts.map +1 -0
  205. package/dist/src/option/__tests__/global.spec.js +121 -0
  206. package/dist/src/option/__tests__/global.spec.js.map +1 -0
  207. package/dist/src/option/__tests__/option.spec.d.ts +2 -0
  208. package/dist/src/option/__tests__/option.spec.d.ts.map +1 -0
  209. package/dist/src/option/__tests__/option.spec.js +111 -0
  210. package/dist/src/option/__tests__/option.spec.js.map +1 -0
  211. package/dist/src/option/find.d.ts +14 -0
  212. package/dist/src/option/find.d.ts.map +1 -0
  213. package/dist/src/option/find.js +17 -0
  214. package/dist/src/option/find.js.map +1 -0
  215. package/dist/src/option/index.d.ts +65 -0
  216. package/dist/src/option/index.d.ts.map +1 -0
  217. package/dist/src/option/index.js +230 -0
  218. package/dist/src/option/index.js.map +1 -0
  219. package/dist/src/option/mapping.d.ts +7 -0
  220. package/dist/src/option/mapping.d.ts.map +1 -0
  221. package/dist/src/option/mapping.js +21 -0
  222. package/dist/src/option/mapping.js.map +1 -0
  223. package/dist/src/option/utils.d.ts +35 -0
  224. package/dist/src/option/utils.d.ts.map +1 -0
  225. package/dist/src/option/utils.js +139 -0
  226. package/dist/src/option/utils.js.map +1 -0
  227. package/dist/src/option/validate.d.ts +15 -0
  228. package/dist/src/option/validate.d.ts.map +1 -0
  229. package/dist/src/option/validate.js +63 -0
  230. package/dist/src/option/validate.js.map +1 -0
  231. package/dist/src/parser/__tests__/parser.spec.d.ts +2 -0
  232. package/dist/src/parser/__tests__/parser.spec.d.ts.map +1 -0
  233. package/dist/src/parser/__tests__/parser.spec.js +343 -0
  234. package/dist/src/parser/__tests__/parser.spec.js.map +1 -0
  235. package/dist/src/parser/index.d.ts +17 -0
  236. package/dist/src/parser/index.d.ts.map +1 -0
  237. package/dist/src/parser/index.js +299 -0
  238. package/dist/src/parser/index.js.map +1 -0
  239. package/dist/src/program/__tests__/program.spec.d.ts +2 -0
  240. package/dist/src/program/__tests__/program.spec.d.ts.map +1 -0
  241. package/dist/src/program/__tests__/program.spec.js +261 -0
  242. package/dist/src/program/__tests__/program.spec.js.map +1 -0
  243. package/dist/src/program/index.d.ts +349 -0
  244. package/dist/src/program/index.d.ts.map +1 -0
  245. package/dist/src/program/index.js +584 -0
  246. package/dist/src/program/index.js.map +1 -0
  247. package/dist/src/types.d.ts +396 -0
  248. package/dist/src/types.d.ts.map +1 -0
  249. package/dist/src/types.js +51 -0
  250. package/dist/src/types.js.map +1 -0
  251. package/dist/src/utils/__tests__/fs.spec.d.ts +2 -0
  252. package/dist/src/utils/__tests__/fs.spec.d.ts.map +1 -0
  253. package/dist/src/utils/__tests__/fs.spec.js +14 -0
  254. package/dist/src/utils/__tests__/fs.spec.js.map +1 -0
  255. package/dist/src/utils/__tests__/levenshtein.spec.d.ts +2 -0
  256. package/dist/src/utils/__tests__/levenshtein.spec.d.ts.map +1 -0
  257. package/dist/src/utils/__tests__/levenshtein.spec.js +18 -0
  258. package/dist/src/utils/__tests__/levenshtein.spec.js.map +1 -0
  259. package/dist/src/utils/__tests__/suggest.spec.d.ts +2 -0
  260. package/dist/src/utils/__tests__/suggest.spec.d.ts.map +1 -0
  261. package/dist/src/utils/__tests__/suggest.spec.js +31 -0
  262. package/dist/src/utils/__tests__/suggest.spec.js.map +1 -0
  263. package/dist/src/utils/colorize.d.ts +2 -0
  264. package/dist/src/utils/colorize.d.ts.map +1 -0
  265. package/dist/src/utils/colorize.js +27 -0
  266. package/dist/src/utils/colorize.js.map +1 -0
  267. package/dist/src/utils/fs.d.ts +2 -0
  268. package/dist/src/utils/fs.d.ts.map +1 -0
  269. package/dist/src/utils/fs.js +19 -0
  270. package/dist/src/utils/fs.js.map +1 -0
  271. package/dist/src/utils/levenshtein.d.ts +6 -0
  272. package/dist/src/utils/levenshtein.d.ts.map +1 -0
  273. package/dist/src/utils/levenshtein.js +32 -0
  274. package/dist/src/utils/levenshtein.js.map +1 -0
  275. package/dist/src/utils/suggest.d.ts +15 -0
  276. package/dist/src/utils/suggest.d.ts.map +1 -0
  277. package/dist/src/utils/suggest.js +49 -0
  278. package/dist/src/utils/suggest.js.map +1 -0
  279. package/dist/src/utils/version.d.ts +2 -0
  280. package/dist/src/utils/version.d.ts.map +1 -0
  281. package/dist/src/utils/version.js +21 -0
  282. package/dist/src/utils/version.js.map +1 -0
  283. package/dist/src/utils/web/autocomplete.d.ts +12 -0
  284. package/dist/src/utils/web/autocomplete.d.ts.map +1 -0
  285. package/dist/src/utils/web/autocomplete.js +12 -0
  286. package/dist/src/utils/web/autocomplete.js.map +1 -0
  287. package/dist/src/utils/web/process.d.ts +15 -0
  288. package/dist/src/utils/web/process.d.ts.map +1 -0
  289. package/dist/src/utils/web/process.js +29 -0
  290. package/dist/src/utils/web/process.js.map +1 -0
  291. package/dist/src/validator/__tests__/array.spec.d.ts +2 -0
  292. package/dist/src/validator/__tests__/array.spec.d.ts.map +1 -0
  293. package/dist/src/validator/__tests__/array.spec.js +34 -0
  294. package/dist/src/validator/__tests__/array.spec.js.map +1 -0
  295. package/dist/src/validator/__tests__/caporal.spec.d.ts +2 -0
  296. package/dist/src/validator/__tests__/caporal.spec.d.ts.map +1 -0
  297. package/dist/src/validator/__tests__/caporal.spec.js +86 -0
  298. package/dist/src/validator/__tests__/caporal.spec.js.map +1 -0
  299. package/dist/src/validator/__tests__/function.spec.d.ts +2 -0
  300. package/dist/src/validator/__tests__/function.spec.d.ts.map +1 -0
  301. package/dist/src/validator/__tests__/function.spec.js +42 -0
  302. package/dist/src/validator/__tests__/function.spec.js.map +1 -0
  303. package/dist/src/validator/__tests__/regexp.spec.d.ts +2 -0
  304. package/dist/src/validator/__tests__/regexp.spec.d.ts.map +1 -0
  305. package/dist/src/validator/__tests__/regexp.spec.js +34 -0
  306. package/dist/src/validator/__tests__/regexp.spec.js.map +1 -0
  307. package/dist/src/validator/__tests__/utils.spec.d.ts +2 -0
  308. package/dist/src/validator/__tests__/utils.spec.d.ts.map +1 -0
  309. package/dist/src/validator/__tests__/utils.spec.js +66 -0
  310. package/dist/src/validator/__tests__/utils.spec.js.map +1 -0
  311. package/dist/src/validator/__tests__/validate.spec.d.ts +2 -0
  312. package/dist/src/validator/__tests__/validate.spec.d.ts.map +1 -0
  313. package/dist/src/validator/__tests__/validate.spec.js +25 -0
  314. package/dist/src/validator/__tests__/validate.spec.js.map +1 -0
  315. package/dist/src/validator/array.d.ts +14 -0
  316. package/dist/src/validator/array.d.ts.map +1 -0
  317. package/dist/src/validator/array.js +29 -0
  318. package/dist/src/validator/array.js.map +1 -0
  319. package/dist/src/validator/caporal.d.ts +25 -0
  320. package/dist/src/validator/caporal.d.ts.map +1 -0
  321. package/dist/src/validator/caporal.js +89 -0
  322. package/dist/src/validator/caporal.js.map +1 -0
  323. package/dist/src/validator/function.d.ts +7 -0
  324. package/dist/src/validator/function.d.ts.map +1 -0
  325. package/dist/src/validator/function.js +27 -0
  326. package/dist/src/validator/function.js.map +1 -0
  327. package/dist/src/validator/regexp.d.ts +14 -0
  328. package/dist/src/validator/regexp.d.ts.map +1 -0
  329. package/dist/src/validator/regexp.js +31 -0
  330. package/dist/src/validator/regexp.js.map +1 -0
  331. package/dist/src/validator/utils.d.ts +14 -0
  332. package/dist/src/validator/utils.d.ts.map +1 -0
  333. package/dist/src/validator/utils.js +81 -0
  334. package/dist/src/validator/utils.js.map +1 -0
  335. package/dist/src/validator/validate.d.ts +7 -0
  336. package/dist/src/validator/validate.d.ts.map +1 -0
  337. package/dist/src/validator/validate.js +29 -0
  338. package/dist/src/validator/validate.js.map +1 -0
  339. package/dist/tsconfig.tsbuildinfo +1 -0
  340. package/package.json +75 -0
  341. package/src/__tests__/issue-163.spec.ts +18 -0
  342. package/src/argument/__tests__/argument.spec.ts +84 -0
  343. package/src/argument/find.ts +11 -0
  344. package/src/argument/index.ts +35 -0
  345. package/src/argument/synopsis.ts +41 -0
  346. package/src/argument/validate.ts +176 -0
  347. package/src/autocomplete/__fixtures__/prog-autocomplete.ts +24 -0
  348. package/src/autocomplete/__tests__/autocomplete.spec.ts +129 -0
  349. package/src/autocomplete/index.ts +225 -0
  350. package/src/autocomplete/types.ts +29 -0
  351. package/src/command/__fixtures__/example-cmd.ts +14 -0
  352. package/src/command/__tests__/command.spec.ts +621 -0
  353. package/src/command/__tests__/find.spec.ts +32 -0
  354. package/src/command/__tests__/import.spec.ts +14 -0
  355. package/src/command/__tests__/scan.spec.ts +16 -0
  356. package/src/command/find.ts +57 -0
  357. package/src/command/import.ts +13 -0
  358. package/src/command/index.ts +458 -0
  359. package/src/command/scan.ts +30 -0
  360. package/src/command/validate-call.ts +19 -0
  361. package/src/config/index.ts +26 -0
  362. package/src/error/__tests__/fatal.spec.ts +38 -0
  363. package/src/error/action.ts +13 -0
  364. package/src/error/base.ts +20 -0
  365. package/src/error/fatal.ts +25 -0
  366. package/src/error/index.ts +17 -0
  367. package/src/error/invalid-validator.ts +12 -0
  368. package/src/error/missing-argument.ts +16 -0
  369. package/src/error/missing-flag.ts +16 -0
  370. package/src/error/multi-validation.ts +22 -0
  371. package/src/error/no-action.ts +19 -0
  372. package/src/error/option-synopsis-syntax.ts +12 -0
  373. package/src/error/too-many-arguments.ts +28 -0
  374. package/src/error/unknown-command.ts +41 -0
  375. package/src/error/unknown-option.ts +40 -0
  376. package/src/error/validation.ts +80 -0
  377. package/src/help/__tests__/__snapshots__/help.spec.ts.snap +334 -0
  378. package/src/help/__tests__/help.spec.ts +144 -0
  379. package/src/help/__tests__/utils.spec.ts +14 -0
  380. package/src/help/index.ts +107 -0
  381. package/src/help/templates/command.ts +27 -0
  382. package/src/help/templates/custom.ts +25 -0
  383. package/src/help/templates/header.ts +19 -0
  384. package/src/help/templates/index.ts +9 -0
  385. package/src/help/templates/program.ts +21 -0
  386. package/src/help/templates/usage.ts +24 -0
  387. package/src/help/types.ts +57 -0
  388. package/src/help/utils.ts +109 -0
  389. package/src/index.ts +93 -0
  390. package/src/logger/__tests__/logger.spec.ts +65 -0
  391. package/src/logger/index.ts +97 -0
  392. package/src/option/__tests__/global.spec.ts +141 -0
  393. package/src/option/__tests__/option.spec.ts +115 -0
  394. package/src/option/find.ts +17 -0
  395. package/src/option/index.ts +280 -0
  396. package/src/option/mapping.ts +17 -0
  397. package/src/option/utils.ts +141 -0
  398. package/src/option/validate.ts +80 -0
  399. package/src/parser/__tests__/parser.spec.ts +371 -0
  400. package/src/parser/index.ts +383 -0
  401. package/src/program/__tests__/program.spec.ts +316 -0
  402. package/src/program/index.ts +676 -0
  403. package/src/types.ts +432 -0
  404. package/src/utils/__tests__/fs.spec.ts +14 -0
  405. package/src/utils/__tests__/levenshtein.spec.ts +16 -0
  406. package/src/utils/__tests__/suggest.spec.ts +30 -0
  407. package/src/utils/colorize.ts +21 -0
  408. package/src/utils/fs.ts +13 -0
  409. package/src/utils/levenshtein.ts +28 -0
  410. package/src/utils/suggest.ts +52 -0
  411. package/src/utils/version.ts +14 -0
  412. package/src/utils/web/autocomplete.ts +19 -0
  413. package/src/utils/web/process.ts +24 -0
  414. package/src/validator/__tests__/array.spec.ts +41 -0
  415. package/src/validator/__tests__/caporal.spec.ts +132 -0
  416. package/src/validator/__tests__/function.spec.ts +52 -0
  417. package/src/validator/__tests__/regexp.spec.ts +38 -0
  418. package/src/validator/__tests__/utils.spec.ts +67 -0
  419. package/src/validator/__tests__/validate.spec.ts +24 -0
  420. package/src/validator/array.ts +31 -0
  421. package/src/validator/caporal.ts +104 -0
  422. package/src/validator/function.ts +31 -0
  423. package/src/validator/regexp.ts +34 -0
  424. package/src/validator/utils.ts +84 -0
  425. package/src/validator/validate.ts +38 -0
@@ -0,0 +1,383 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module parser
4
+ */
5
+ import invert from "lodash/invert"
6
+ import findIndex from "lodash/findIndex"
7
+ import type {
8
+ ParserOptions,
9
+ ParserResult,
10
+ ParserTypes,
11
+ ParsedOptions,
12
+ ParsedArguments,
13
+ } from "../types"
14
+ import {
15
+ isNumeric,
16
+ isConcatenatedOpt,
17
+ isNegativeOpt,
18
+ isOptionStr,
19
+ formatOptName,
20
+ isOptArray,
21
+ } from "../option/utils"
22
+
23
+ const DDASH = "--"
24
+
25
+ function isDdash(str?: string): str is string {
26
+ return str === DDASH
27
+ }
28
+
29
+ function castAsBool(value: string | boolean): boolean {
30
+ if (typeof value === "boolean") {
31
+ return value
32
+ }
33
+ return /^true|1|yes|on$/.test(value)
34
+ }
35
+
36
+ function castAsString(val: string | boolean): string {
37
+ return val + ""
38
+ }
39
+
40
+ function autoCast(val: string): ParserTypes {
41
+ // auto-casting "true" & "false"
42
+ if (/^true|false$/.test(val)) {
43
+ return val === "true"
44
+ }
45
+ // auto-casting numbers
46
+ return isNumeric(val) ? parseFloat(val) : val
47
+ }
48
+
49
+ function cast(name: string, val: string | true, options: ParserOptions): ParserTypes {
50
+ const cleanName = formatOptName(name)
51
+
52
+ // Force casting to string
53
+ if (options.string.includes(cleanName)) {
54
+ return castAsString(val)
55
+ }
56
+
57
+ // Force casting to bool
58
+ if (options.boolean.includes(cleanName) || typeof val === "boolean") {
59
+ return castAsBool(val)
60
+ }
61
+
62
+ return options.autoCast ? autoCast(val) : val
63
+ }
64
+
65
+ /**
66
+ * Parse a line
67
+ *
68
+ * @param line Line to be parsed
69
+ * @param options Parser options
70
+ * @internal
71
+ */
72
+ export function parseLine(
73
+ line: string,
74
+ options: Partial<ParserOptions> = {},
75
+ ): ParserResult {
76
+ return parseArgv(options, line.split(" "))
77
+ }
78
+ /**
79
+ *
80
+ * @param args Return the next option position unless there is some ddash before
81
+ */
82
+ function getNextOptPosition(args: string[]): number {
83
+ const ddash = args.indexOf("--")
84
+ const opt = findIndex(args, isOptionStr)
85
+ return ddash < opt && ddash !== -1 ? -1 : opt
86
+ }
87
+
88
+ class Tree {
89
+ cursor: number
90
+ private ddashHandled = false
91
+
92
+ constructor(private argv: string[]) {
93
+ this.cursor = 0
94
+ }
95
+
96
+ /* istanbul ignore next */
97
+ toJSON(): {
98
+ cursor: number
99
+ ddashHandled: boolean
100
+ argv: string[]
101
+ current?: string
102
+ } {
103
+ return {
104
+ cursor: this.cursor,
105
+ ddashHandled: this.ddashHandled,
106
+ current: this.current,
107
+ argv: this.argv,
108
+ }
109
+ }
110
+
111
+ markDdashHandled(): Tree {
112
+ this.ddashHandled = true
113
+ return this
114
+ }
115
+
116
+ hasDdashHandled(): boolean {
117
+ return this.ddashHandled
118
+ }
119
+
120
+ next(): string | undefined {
121
+ return this.argv[this.cursor + 1]
122
+ }
123
+
124
+ slice(start?: number, end?: number): string[] {
125
+ return this.argv.slice(start, end)
126
+ }
127
+
128
+ sliceFromHere(end?: number): string[] {
129
+ return this.slice(this.cursor, end)
130
+ }
131
+
132
+ forward(by = 1): true {
133
+ if (by === -1) {
134
+ return this.end()
135
+ }
136
+ this.cursor += by
137
+ return true
138
+ }
139
+
140
+ end(): true {
141
+ this.cursor = this.length
142
+ return true
143
+ }
144
+
145
+ get current(): string | undefined {
146
+ return this.argv[this.cursor]
147
+ }
148
+
149
+ get length(): number {
150
+ return this.argv.length
151
+ }
152
+ }
153
+
154
+ class ArgumentParser {
155
+ public readonly args: ParsedArguments = []
156
+ public readonly ddash: ParsedArguments = []
157
+ public readonly rawArgv: string[]
158
+ public readonly line: string
159
+ private variadicId?: number
160
+ private key: "args" | "ddash" = "args"
161
+
162
+ constructor(
163
+ private config: ParserOptions,
164
+ argv: string[],
165
+ ) {
166
+ this.line = argv.join(" ")
167
+ this.rawArgv = argv
168
+ }
169
+
170
+ toJSON(): {
171
+ args: ParsedArguments
172
+ ddash: ParsedArguments
173
+ rawArgv: string[]
174
+ line: string
175
+ } {
176
+ return {
177
+ args: this.args,
178
+ ddash: this.ddash,
179
+ rawArgv: this.rawArgv,
180
+ line: this.line,
181
+ }
182
+ }
183
+
184
+ inVariadicContext(): boolean | undefined {
185
+ const argsLen = this[this.key].length
186
+ if (this.config.variadic.includes(argsLen)) {
187
+ this.variadicId = argsLen
188
+ }
189
+ if (this.variadicId !== undefined) {
190
+ return true
191
+ }
192
+ return undefined
193
+ }
194
+
195
+ markDdashHandled(tree: Tree): true {
196
+ if (this.config.ddash) {
197
+ // if ddash enabled, update the key
198
+ this.key = "ddash"
199
+ }
200
+ return tree.markDdashHandled().forward()
201
+ }
202
+
203
+ push(...values: string[]): true {
204
+ this[this.key].push(...values.map(this.config.autoCast ? autoCast : String))
205
+ return true
206
+ }
207
+
208
+ pushVariadic(tree: Tree): true {
209
+ const args = tree.sliceFromHere()
210
+ const until = getNextOptPosition(args)
211
+ this.variadicId = this.variadicId || 0
212
+ const variadic = (this[this.key][this.variadicId] =
213
+ (this[this.key][this.variadicId] as ParserTypes[]) || [])
214
+
215
+ variadic.push(
216
+ ...args
217
+ .slice(0, until === -1 ? undefined : until)
218
+ .filter((s: string) => !isDdash(s))
219
+ .map(this.config.autoCast ? autoCast : String),
220
+ )
221
+
222
+ return tree.forward(until)
223
+ }
224
+
225
+ visit(tree: Tree): unknown {
226
+ if (!tree.current || (isOptionStr(tree.current) && !tree.hasDdashHandled())) {
227
+ return false
228
+ }
229
+ if (isDdash(tree.current)) {
230
+ return this.markDdashHandled(tree)
231
+ } else if (!this.inVariadicContext()) {
232
+ this.push(tree.current)
233
+ return tree.forward()
234
+ }
235
+ return this.pushVariadic(tree)
236
+ }
237
+ }
238
+
239
+ class OptionParser {
240
+ public readonly options: ParsedOptions = {}
241
+ public readonly rawOptions: ParsedOptions = {}
242
+
243
+ constructor(private config: ParserOptions) {}
244
+
245
+ toJSON(): {
246
+ options: ParsedOptions
247
+ rawOptions: ParsedOptions
248
+ } {
249
+ return {
250
+ options: this.options,
251
+ rawOptions: this.rawOptions,
252
+ }
253
+ }
254
+
255
+ handleOptWithoutValue(name: string, tree: Tree): void {
256
+ const next = tree.next()
257
+ const nextIsOptOrUndef = isOptionStr(next) || isDdash(next) || next === undefined
258
+ this.compute(
259
+ name,
260
+ cast(name, nextIsOptOrUndef ? true : (next as string), this.config),
261
+ )
262
+ if (!nextIsOptOrUndef) {
263
+ tree.forward()
264
+ }
265
+ }
266
+
267
+ handleConcatenatedOpts(tree: Tree, names: string[], val?: ParserTypes): void {
268
+ if (val === undefined) {
269
+ val = true
270
+ const next = tree.next()
271
+ const last = names[names.length - 1]
272
+ const alias = this.config.alias[last]
273
+ const shouldTakeNextAsVal =
274
+ next && !isOptionStr(next) && !isDdash(next) && !this.isBoolean(last, alias)
275
+ if (shouldTakeNextAsVal) {
276
+ tree.forward()
277
+ val = next as string
278
+ }
279
+ }
280
+ this.computeMulti(names, val)
281
+ }
282
+
283
+ visit(tree: Tree): boolean {
284
+ // only handle options
285
+ /* istanbul ignore if */
286
+ if (!tree.current || !isOptionStr(tree.current) || tree.hasDdashHandled()) {
287
+ // this is never reached because the scan stops if
288
+ // a visior returns true, and as the Argument visitor is the first in the
289
+ // list, arguments objects never reach the Options visitor
290
+ // keeping it here in case we change the order of visitors
291
+ return false
292
+ }
293
+
294
+ const [name, rawval] = tree.current.split("=", 2)
295
+ const concatOpts = isConcatenatedOpt(name)
296
+
297
+ if (concatOpts) {
298
+ this.handleConcatenatedOpts(tree, concatOpts, rawval)
299
+ } else if (rawval) {
300
+ this.compute(name, cast(name, rawval, this.config))
301
+ } else {
302
+ this.handleOptWithoutValue(name, tree)
303
+ }
304
+
305
+ return tree.forward()
306
+ }
307
+
308
+ compute(name: string, val: ParserTypes): void {
309
+ const no = isNegativeOpt(name)
310
+ const cleanName = formatOptName(name)
311
+ const alias = this.config.alias[cleanName]
312
+
313
+ if (this.isVariadic(cleanName, alias)) {
314
+ const prop = this.options[cleanName]
315
+ this.rawOptions[name] = this.options[cleanName] = (
316
+ isOptArray(prop) ? prop : [prop]
317
+ ).concat(val)
318
+ } else {
319
+ this.rawOptions[name] = this.options[cleanName] = no ? !val : val
320
+ }
321
+ if (alias) {
322
+ this.options[alias] = this.options[cleanName]
323
+ }
324
+ }
325
+
326
+ // todo: handle variadic, even for compute multi
327
+ // TIP: (maybe just split and redirect the last char to compute())
328
+ computeMulti(multi: string[], val: ParserTypes): void {
329
+ const n = multi.length
330
+ multi.forEach((o, index) => {
331
+ const alias = this.config.alias[o]
332
+ this.options[o] = index + 1 === n ? cast(o, val as string, this.config) : true
333
+ this.rawOptions["-" + o] = this.options[o]
334
+ if (alias) {
335
+ this.options[alias] = this.options[o]
336
+ }
337
+ })
338
+ }
339
+
340
+ isVariadic(name: string, alias: string): boolean {
341
+ return (
342
+ name in this.options &&
343
+ (this.config.variadic.includes(name) || this.config.variadic.includes(alias))
344
+ )
345
+ }
346
+
347
+ isBoolean(name: string, alias: string): boolean {
348
+ return this.config.boolean.includes(name) || this.config.boolean.includes(alias)
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Parse command line arguments
354
+ *
355
+ * @param options Parser options
356
+ * @param argv command line arguments array (a.k.a. "argv")
357
+ */
358
+ export function parseArgv(
359
+ options: Partial<ParserOptions> = {},
360
+ argv: string[] = process.argv.slice(2),
361
+ ): ParserResult {
362
+ const parseOpts: ParserOptions = {
363
+ autoCast: true,
364
+ ddash: false,
365
+ alias: {},
366
+ boolean: [],
367
+ string: [],
368
+ variadic: [],
369
+ ...options,
370
+ }
371
+ parseOpts.alias = { ...parseOpts.alias, ...invert(parseOpts.alias) }
372
+
373
+ const tree = new Tree(argv)
374
+ const flagParser = new OptionParser(parseOpts)
375
+ const argParser = new ArgumentParser(parseOpts, argv)
376
+ const visitors = [argParser, flagParser]
377
+
378
+ while (tree.current) {
379
+ visitors.some((v) => v.visit(tree))
380
+ }
381
+
382
+ return { ...flagParser.toJSON(), ...argParser.toJSON() }
383
+ }
@@ -0,0 +1,316 @@
1
+ import { expect, it, describe, beforeEach, vi } from "vitest"
2
+
3
+ const mocks = vi.hoisted(() => {
4
+ return {
5
+ fatalError: vi.fn(),
6
+ }
7
+ })
8
+
9
+ vi.mock("../../error/fatal", () => ({
10
+ fatalError: mocks.fatalError,
11
+ }))
12
+
13
+ vi.useFakeTimers()
14
+
15
+ import { program } from "../../index"
16
+ import { Program } from ".."
17
+ import {
18
+ UnknownOrUnspecifiedCommandError,
19
+ ValidationSummaryError,
20
+ NoActionError,
21
+ } from "../../error"
22
+ import { Logger } from "../../types"
23
+ import { logger } from "../../logger"
24
+ import { resetGlobalOptions } from "../../option"
25
+
26
+ let prog = program
27
+
28
+ const loggerWarnSpy = vi.spyOn(logger, "warn")
29
+
30
+ describe("Program", () => {
31
+ beforeEach(() => {
32
+ prog = new Program()
33
+ prog.name("test-prog")
34
+ prog.bin("test-prog")
35
+ vi.clearAllMocks()
36
+ resetGlobalOptions()
37
+ })
38
+
39
+ it(".version() should set the version", () => {
40
+ prog.version("beta-2")
41
+ expect(prog.getVersion()).toBe("beta-2")
42
+ })
43
+
44
+ it(".description() should set the description", () => {
45
+ prog.description("fake-desc")
46
+ expect(prog.getDescription()).toBe("fake-desc")
47
+ })
48
+
49
+ it(".hasCommands() should return false by default", () => {
50
+ return expect(prog.hasCommands()).resolves.toBe(false)
51
+ })
52
+
53
+ it(".getSynopsis should return the correct synopsis if program has commands", () => {
54
+ const action = vi.fn().mockReturnValue("ok")
55
+ prog.command("my-command", "my command").action(action)
56
+ return expect(prog.getSynopsis()).resolves.toContain("<command>")
57
+ })
58
+
59
+ it(".synospis should return the correct synopsis if program does not have commands", () => {
60
+ const action = vi.fn().mockReturnValue("ok")
61
+ prog.action(action)
62
+ return expect(prog.getSynopsis()).resolves.not.toContain("<command>")
63
+ })
64
+
65
+ it(".parse(undefined) should work", async () => {
66
+ const action = vi.fn().mockReturnValue("ok")
67
+ prog.argument("[first-arg]", "First argument").action(action)
68
+ await expect(prog.run([])).resolves.toBe("ok")
69
+ expect(action).toHaveBeenCalled()
70
+ })
71
+
72
+ it("should be able to create a 'program-command' just by calling .argument()", async () => {
73
+ const action = vi.fn().mockReturnValue("ok")
74
+ prog.argument("<first-arg>", "First argument").action(action)
75
+ await expect(prog.run(["first-arg"])).resolves.toBe("ok")
76
+ expect(action).toHaveBeenCalled()
77
+ })
78
+
79
+ it("should be able to create a 'program-command' just by calling .option()", async () => {
80
+ const action = vi.fn().mockReturnValue("ok")
81
+ prog.option("--foo", "Foo option").action(action)
82
+ await expect(prog.run(["--foo"])).resolves.toBe("ok")
83
+ expect(action).toHaveBeenCalled()
84
+ })
85
+
86
+ it(".globalOption() should create a global option without associated action", async () => {
87
+ const action = vi.fn().mockReturnValue("ok")
88
+ prog.option("--my-global <var>", "my global var", { global: true })
89
+ prog.argument("<first-arg>", "First argument").action(action)
90
+
91
+ await expect(prog.run(["first-arg", "--my-global", "secret"])).resolves.toBe("ok")
92
+ expect(action).toHaveBeenCalled()
93
+ })
94
+
95
+ it(".globalOption() should create a global option with associated action", async () => {
96
+ const action = vi.fn().mockReturnValue("ok")
97
+ const optAction = vi.fn()
98
+ prog.option("--my-global <var>", "my global var", { global: true, action: optAction })
99
+ prog.argument("<first-arg>", "First argument").action(action)
100
+
101
+ await expect(prog.run(["first-arg", "--my-global", "secret"])).resolves.toBe("ok")
102
+ expect(action).toHaveBeenCalled()
103
+ expect(optAction).toHaveBeenCalled()
104
+ })
105
+
106
+ it("disableGlobalOption() should disable a global option", async () => {
107
+ const action = vi.fn().mockReturnValue("ok")
108
+ const optAction = vi.fn()
109
+ prog.option("--my-global <var>", "my global var", { global: true, action: optAction })
110
+ prog.argument("<first-arg>", "First argument").action(action)
111
+ prog.strict(false)
112
+ prog.disableGlobalOption("myGlobal")
113
+
114
+ // second call should call console.warn
115
+ prog.disableGlobalOption("myGlobal")
116
+
117
+ await expect(prog.run(["first-arg", "--my-global", "secret"])).resolves.toBe("ok")
118
+ expect(action).toHaveBeenCalled()
119
+ expect(optAction).not.toHaveBeenCalled()
120
+ expect(loggerWarnSpy).toHaveBeenCalled()
121
+ })
122
+
123
+ it(".discover() should set discovery path if it exists", () => {
124
+ prog.discover(".")
125
+ expect(prog.discoveryPath).toBe(".")
126
+ })
127
+
128
+ it(".discover() should throw if provided path does not exist", () => {
129
+ return expect(() => prog.discover("/unknown/path")).toThrowError()
130
+ })
131
+
132
+ it(".discover() should throw if provided path is not a directory", () => {
133
+ return expect(() => prog.discover(__filename)).toThrowError()
134
+ })
135
+
136
+ it("should be able to call discovered commands", async () => {
137
+ prog.discover(__dirname + "/../../command/__fixtures__")
138
+ await expect(prog.run(["example-cmd"])).resolves.toBe("hey")
139
+ })
140
+
141
+ it("should be able to call .argument() multiple times", async () => {
142
+ const action = vi.fn().mockReturnValue("ok")
143
+ prog.argument("<first-arg>", "First argument").action(action)
144
+ prog.argument("<second-arg>", "Second argument").action(action)
145
+ await expect(prog.run(["first-arg", "sec-arg"])).resolves.toBe("ok")
146
+ expect(action).toHaveBeenCalled()
147
+ })
148
+
149
+ it(".run() should work without arguments", async () => {
150
+ const action = vi.fn().mockReturnValue("ok")
151
+ prog.strict(false)
152
+ prog.action(action)
153
+ await expect(prog.run()).resolves.toBe("ok")
154
+ })
155
+
156
+ it(".run() should throw an Error when no action is defined for the program-command", async () => {
157
+ prog.option("-t, --type <pizza-type>", "Pizza type")
158
+ await expect(prog.run([])).rejects.toBeInstanceOf(NoActionError)
159
+ })
160
+
161
+ it("should be able to create a 'program-command' just by calling .action()", async () => {
162
+ const action = vi.fn().mockReturnValue("ok")
163
+ prog.action(action)
164
+ await expect(prog.run([])).resolves.toBe("ok")
165
+ expect(action).toHaveBeenCalled()
166
+ })
167
+
168
+ it(".exec() should work as expected", async () => {
169
+ const action = vi.fn().mockReturnValue("ok")
170
+ prog.argument("<first-arg>", "First argument").action(action)
171
+ await expect(prog.exec(["1"])).resolves.toBe("ok")
172
+ expect(action).toHaveBeenCalledWith(
173
+ expect.objectContaining({
174
+ args: {
175
+ firstArg: "1",
176
+ },
177
+ }),
178
+ )
179
+ })
180
+
181
+ it(".cast(true) should enable auto casting", async () => {
182
+ const action = vi.fn().mockReturnValue("ok")
183
+ prog.argument("<first-arg>", "First argument").action(action)
184
+ prog.cast(true)
185
+ await expect(prog.run(["1"])).resolves.toBe("ok")
186
+ expect(action).toHaveBeenCalledWith(
187
+ expect.objectContaining({
188
+ args: {
189
+ firstArg: 1,
190
+ },
191
+ }),
192
+ )
193
+ })
194
+
195
+ it(".cast(false) should disable auto casting", async () => {
196
+ const action = vi.fn().mockReturnValue("ok")
197
+ prog.argument("<first-arg>", "First argument").action(action)
198
+ prog.cast(false)
199
+ await expect(prog.run(["1"])).resolves.toBe("ok")
200
+ expect(action).toHaveBeenCalledWith(
201
+ expect.objectContaining({
202
+ args: {
203
+ firstArg: "1",
204
+ },
205
+ }),
206
+ )
207
+ })
208
+
209
+ it("program should create help command and accept executing 'program help'", async () => {
210
+ const action = vi.fn().mockReturnValue("ok")
211
+ prog
212
+ .command("test", "test command")
213
+ .argument("<first-arg>", "First argument")
214
+ .action(action)
215
+ await expect(prog.run(["help"])).resolves.toBe(-1)
216
+ await expect(prog.run(["help", "test"])).resolves.toBe(-1)
217
+ expect(action).not.toHaveBeenCalled()
218
+ expect(mocks.fatalError).not.toHaveBeenCalled()
219
+ })
220
+
221
+ it("program should create help command and accept executing 'program help command-name'", async () => {
222
+ const action = vi.fn().mockReturnValue("ok")
223
+ prog
224
+ .command("test", "test command")
225
+ .argument("<first-arg>", "First argument")
226
+ .action(action)
227
+ await expect(prog.run(["help", "test"])).resolves.toBe(-1)
228
+ expect(action).not.toHaveBeenCalled()
229
+ expect(mocks.fatalError).not.toHaveBeenCalled()
230
+ })
231
+
232
+ it("program should create help command and accept executing 'program help unknown-command'", async () => {
233
+ const action = vi.fn().mockReturnValue("ok")
234
+ prog
235
+ .command("test", "test command")
236
+ .argument("<first-arg>", "First argument")
237
+ .action(action)
238
+ await expect(prog.run(["help", "unknown"])).resolves.toBe(-1)
239
+ expect(action).not.toHaveBeenCalled()
240
+ expect(mocks.fatalError).not.toHaveBeenCalled()
241
+ })
242
+
243
+ it("'program help' should work for a program without any command", async () => {
244
+ const action = vi.fn().mockReturnValue("ok")
245
+ prog.bin("test").argument("<first-arg>", "First argument").action(action)
246
+ await expect(prog.run(["help"])).resolves.toBe(-1)
247
+ expect(action).not.toHaveBeenCalled()
248
+ expect(mocks.fatalError).not.toHaveBeenCalled()
249
+ })
250
+
251
+ it("'program' should throw for a program without any command but a required arg", async () => {
252
+ const action = vi.fn().mockReturnValue("ok")
253
+ prog.bin("test").argument("<first-arg>", "First argument").action(action)
254
+ await expect(prog.run([])).rejects.toBeInstanceOf(ValidationSummaryError)
255
+ expect(action).not.toHaveBeenCalled()
256
+ })
257
+
258
+ it("program should fail when trying to run an unknown command", async () => {
259
+ const action = vi.fn().mockReturnValue("ok")
260
+ prog
261
+ .command("test", "test command")
262
+ .argument("<first-arg>", "First argument")
263
+ .action(action)
264
+ await expect(prog.run(["unknown-cmd"])).rejects.toBeInstanceOf(
265
+ UnknownOrUnspecifiedCommandError,
266
+ )
267
+ })
268
+
269
+ it("program should fail when trying to run an unknown command and suggest some commands", async () => {
270
+ const action = vi.fn().mockReturnValue("ok")
271
+ prog
272
+ .command("test", "test command")
273
+ .argument("<first-arg>", "First argument")
274
+ .action(action)
275
+ await expect(prog.run(["rest"])).rejects.toBeInstanceOf(
276
+ UnknownOrUnspecifiedCommandError,
277
+ )
278
+ })
279
+
280
+ it("program should fail when trying to run without a specified command", async () => {
281
+ const action = vi.fn().mockReturnValue("ok")
282
+ prog
283
+ .command("test", "test command")
284
+ .argument("<first-arg>", "First argument")
285
+ .action(action)
286
+ await expect(prog.run([])).rejects.toBeInstanceOf(UnknownOrUnspecifiedCommandError)
287
+ })
288
+
289
+ it(".setLogLevelEnvVar() should set the log level ENV var", async () => {
290
+ process.env.MY_ENV_VAR = "warn"
291
+ prog.configure({ logLevelEnvVar: "MY_ENV_VAR" })
292
+ const action = vi.fn().mockReturnValue("ok")
293
+ prog
294
+ .command("test", "test command")
295
+ .argument("<first-arg>", "First argument")
296
+ .action(action)
297
+ expect(prog.getLogLevelOverride()).toBe("warn")
298
+ await prog.run(["test", "my-arg"])
299
+ expect(logger.level).toBe("warn")
300
+ })
301
+
302
+ it(".logger() should override the default logger", async () => {
303
+ const action = vi.fn().mockImplementation(({ logger }) => {
304
+ logger.log("foo")
305
+ return true
306
+ })
307
+ const logger = { log: vi.fn() }
308
+ prog
309
+ .logger(logger as unknown as Logger)
310
+ .command("test", "test command")
311
+ .argument("<first-arg>", "First argument")
312
+ .action(action)
313
+ await expect(prog.run(["test", "my-arg"])).resolves.toBe(true)
314
+ expect(logger.log).toHaveBeenCalledWith("foo")
315
+ })
316
+ })