zod-args-parser 1.1.0 → 1.2.1

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 (206) hide show
  1. package/README.md +597 -91
  2. package/lib/commonjs/autocomplete-scripts/bash-autocomplete-script.js +1 -1
  3. package/lib/commonjs/autocomplete-scripts/bash-autocomplete-script.js.map +1 -1
  4. package/lib/commonjs/autocomplete-scripts/powershell-autocomplete-script.js +1 -1
  5. package/lib/commonjs/autocomplete-scripts/powershell-autocomplete-script.js.map +1 -1
  6. package/lib/commonjs/autocomplete-scripts/zsh-autocomplete-script.js +1 -1
  7. package/lib/commonjs/autocomplete-scripts/zsh-autocomplete-script.js.map +1 -1
  8. package/lib/commonjs/help-message/format-arguments.js +1 -0
  9. package/lib/commonjs/help-message/format-arguments.js.map +1 -0
  10. package/lib/commonjs/help-message/format-cli.js +1 -0
  11. package/lib/commonjs/help-message/format-cli.js.map +1 -0
  12. package/lib/commonjs/help-message/format-options.js +1 -0
  13. package/lib/commonjs/help-message/format-options.js.map +1 -0
  14. package/lib/commonjs/help-message/format-subcommands.js +1 -0
  15. package/lib/commonjs/help-message/format-subcommands.js.map +1 -0
  16. package/lib/commonjs/help-message/styles.js +1 -0
  17. package/lib/commonjs/help-message/styles.js.map +1 -0
  18. package/lib/commonjs/index.js +1 -1
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/commonjs/markdown/generate-markdown.js.map +1 -1
  21. package/lib/commonjs/metadata/get-arguments-metadata.js +1 -1
  22. package/lib/commonjs/metadata/get-arguments-metadata.js.map +1 -1
  23. package/lib/commonjs/metadata/get-cli-metadata.js +1 -1
  24. package/lib/commonjs/metadata/get-cli-metadata.js.map +1 -1
  25. package/lib/commonjs/metadata/get-options-metadata.js +1 -1
  26. package/lib/commonjs/metadata/get-options-metadata.js.map +1 -1
  27. package/lib/commonjs/metadata/get-subcommands-metadata.js.map +1 -1
  28. package/lib/commonjs/parser/parse/parse.js +1 -0
  29. package/lib/commonjs/parser/parse/parse.js.map +1 -0
  30. package/lib/commonjs/parser/parse/parser-helpers.js +1 -0
  31. package/lib/commonjs/parser/parse/parser-helpers.js.map +1 -0
  32. package/lib/commonjs/parser/safe-parse.js +1 -1
  33. package/lib/commonjs/parser/safe-parse.js.map +1 -1
  34. package/lib/commonjs/parser/unsafe-parse.js +1 -0
  35. package/lib/commonjs/parser/unsafe-parse.js.map +1 -0
  36. package/lib/commonjs/parser/validate/validate-type.js +1 -0
  37. package/lib/commonjs/parser/validate/validate-type.js.map +1 -0
  38. package/lib/commonjs/parser/validate/validate.js +1 -0
  39. package/lib/commonjs/parser/validate/validate.js.map +1 -0
  40. package/lib/commonjs/utils.js +1 -1
  41. package/lib/commonjs/utils.js.map +1 -1
  42. package/lib/commonjs/zod-utils.js +1 -0
  43. package/lib/commonjs/zod-utils.js.map +1 -0
  44. package/lib/module/autocomplete-scripts/bash-autocomplete-script.js +1 -1
  45. package/lib/module/autocomplete-scripts/bash-autocomplete-script.js.map +1 -1
  46. package/lib/module/autocomplete-scripts/powershell-autocomplete-script.js +1 -1
  47. package/lib/module/autocomplete-scripts/powershell-autocomplete-script.js.map +1 -1
  48. package/lib/module/autocomplete-scripts/zsh-autocomplete-script.js +1 -1
  49. package/lib/module/autocomplete-scripts/zsh-autocomplete-script.js.map +1 -1
  50. package/lib/module/help-message/format-arguments.js +1 -0
  51. package/lib/module/help-message/format-arguments.js.map +1 -0
  52. package/lib/module/help-message/format-cli.js +1 -0
  53. package/lib/module/help-message/format-cli.js.map +1 -0
  54. package/lib/module/help-message/format-options.js +1 -0
  55. package/lib/module/help-message/format-options.js.map +1 -0
  56. package/lib/module/help-message/{print-subcommands.js → format-subcommands.js} +1 -1
  57. package/lib/module/help-message/format-subcommands.js.map +1 -0
  58. package/lib/module/help-message/styles.js +1 -0
  59. package/lib/module/help-message/styles.js.map +1 -0
  60. package/lib/module/index.js +1 -1
  61. package/lib/module/index.js.map +1 -1
  62. package/lib/module/markdown/generate-markdown.js.map +1 -1
  63. package/lib/module/metadata/get-arguments-metadata.js +1 -1
  64. package/lib/module/metadata/get-arguments-metadata.js.map +1 -1
  65. package/lib/module/metadata/get-cli-metadata.js +1 -1
  66. package/lib/module/metadata/get-cli-metadata.js.map +1 -1
  67. package/lib/module/metadata/get-options-metadata.js +1 -1
  68. package/lib/module/metadata/get-options-metadata.js.map +1 -1
  69. package/lib/module/metadata/get-subcommands-metadata.js.map +1 -1
  70. package/lib/module/parser/parse/parse.js +1 -0
  71. package/lib/module/parser/parse/parse.js.map +1 -0
  72. package/lib/module/parser/parse/parser-helpers.js +1 -0
  73. package/lib/module/parser/parse/parser-helpers.js.map +1 -0
  74. package/lib/module/parser/safe-parse.js +1 -1
  75. package/lib/module/parser/safe-parse.js.map +1 -1
  76. package/lib/module/parser/unsafe-parse.js +1 -0
  77. package/lib/module/parser/unsafe-parse.js.map +1 -0
  78. package/lib/module/parser/validate/validate-type.js +1 -0
  79. package/lib/module/parser/validate/validate-type.js.map +1 -0
  80. package/lib/module/parser/validate/validate.js +1 -0
  81. package/lib/module/parser/validate/validate.js.map +1 -0
  82. package/lib/module/utils.js +1 -1
  83. package/lib/module/utils.js.map +1 -1
  84. package/lib/module/zod-utils.js +1 -0
  85. package/lib/module/zod-utils.js.map +1 -0
  86. package/lib/typescript/help-message/format-arguments.d.ts +4 -0
  87. package/lib/typescript/help-message/format-arguments.d.ts.map +1 -0
  88. package/lib/typescript/help-message/format-cli.d.ts +6 -0
  89. package/lib/typescript/help-message/format-cli.d.ts.map +1 -0
  90. package/lib/typescript/help-message/format-options.d.ts +4 -0
  91. package/lib/typescript/help-message/format-options.d.ts.map +1 -0
  92. package/lib/typescript/help-message/format-subcommands.d.ts +4 -0
  93. package/lib/typescript/help-message/format-subcommands.d.ts.map +1 -0
  94. package/lib/typescript/help-message/styles.d.ts +108 -0
  95. package/lib/typescript/help-message/styles.d.ts.map +1 -0
  96. package/lib/typescript/index.d.ts +18 -29
  97. package/lib/typescript/index.d.ts.map +1 -1
  98. package/lib/typescript/markdown/generate-markdown.d.ts.map +1 -1
  99. package/lib/typescript/metadata/get-arguments-metadata.d.ts +2 -1
  100. package/lib/typescript/metadata/get-arguments-metadata.d.ts.map +1 -1
  101. package/lib/typescript/metadata/get-cli-metadata.d.ts +3 -2
  102. package/lib/typescript/metadata/get-cli-metadata.d.ts.map +1 -1
  103. package/lib/typescript/metadata/get-options-metadata.d.ts +2 -1
  104. package/lib/typescript/metadata/get-options-metadata.d.ts.map +1 -1
  105. package/lib/typescript/metadata/get-subcommands-metadata.d.ts +2 -1
  106. package/lib/typescript/metadata/get-subcommands-metadata.d.ts.map +1 -1
  107. package/lib/typescript/metadata/metadata-types.d.ts +80 -0
  108. package/lib/typescript/metadata/metadata-types.d.ts.map +1 -0
  109. package/lib/typescript/parser/parse/parse-types.d.ts +85 -0
  110. package/lib/typescript/parser/parse/parse-types.d.ts.map +1 -0
  111. package/lib/typescript/parser/parse/parse.d.ts +4 -0
  112. package/lib/typescript/parser/parse/parse.d.ts.map +1 -0
  113. package/lib/typescript/parser/parse/parser-helpers.d.ts +40 -0
  114. package/lib/typescript/parser/parse/parser-helpers.d.ts.map +1 -0
  115. package/lib/typescript/parser/safe-parse.d.ts +1 -0
  116. package/lib/typescript/parser/safe-parse.d.ts.map +1 -1
  117. package/lib/typescript/parser/unsafe-parse.d.ts +4 -0
  118. package/lib/typescript/parser/unsafe-parse.d.ts.map +1 -0
  119. package/lib/typescript/parser/validate/validate-type.d.ts +22 -0
  120. package/lib/typescript/parser/validate/validate-type.d.ts.map +1 -0
  121. package/lib/typescript/parser/validate/validate.d.ts +11 -0
  122. package/lib/typescript/parser/validate/validate.d.ts.map +1 -0
  123. package/lib/typescript/types.d.ts +66 -181
  124. package/lib/typescript/types.d.ts.map +1 -1
  125. package/lib/typescript/utils.d.ts +21 -19
  126. package/lib/typescript/utils.d.ts.map +1 -1
  127. package/lib/typescript/zod-utils.d.ts +27 -0
  128. package/lib/typescript/zod-utils.d.ts.map +1 -0
  129. package/package.json +7 -6
  130. package/src/autocomplete-scripts/bash-autocomplete-script.ts +1 -1
  131. package/src/autocomplete-scripts/powershell-autocomplete-script.ts +1 -1
  132. package/src/autocomplete-scripts/zsh-autocomplete-script.ts +1 -1
  133. package/src/help-message/format-arguments.ts +38 -0
  134. package/src/help-message/{print-help-message.ts → format-cli.ts} +43 -48
  135. package/src/help-message/{print-options.ts → format-options.ts} +16 -14
  136. package/src/help-message/format-subcommands.ts +37 -0
  137. package/src/help-message/styles.ts +120 -0
  138. package/src/index.ts +50 -44
  139. package/src/markdown/generate-markdown.ts +2 -1
  140. package/src/metadata/get-arguments-metadata.ts +5 -3
  141. package/src/metadata/get-cli-metadata.ts +4 -4
  142. package/src/metadata/get-options-metadata.ts +6 -4
  143. package/src/metadata/get-subcommands-metadata.ts +2 -1
  144. package/src/metadata/metadata-types.ts +114 -0
  145. package/src/parser/parse/parse-types.ts +89 -0
  146. package/src/parser/parse/parse.ts +227 -0
  147. package/src/parser/parse/parser-helpers.ts +167 -0
  148. package/src/parser/safe-parse.ts +60 -8
  149. package/src/parser/unsafe-parse.ts +98 -0
  150. package/src/parser/validate/validate-type.ts +21 -0
  151. package/src/parser/validate/validate.ts +66 -0
  152. package/src/types.ts +90 -231
  153. package/src/utils.ts +40 -62
  154. package/src/{zodUtils.ts → zod-utils.ts} +65 -17
  155. package/lib/commonjs/help-message/colors.js +0 -1
  156. package/lib/commonjs/help-message/colors.js.map +0 -1
  157. package/lib/commonjs/help-message/print-arguments.js +0 -1
  158. package/lib/commonjs/help-message/print-arguments.js.map +0 -1
  159. package/lib/commonjs/help-message/print-help-message.js +0 -1
  160. package/lib/commonjs/help-message/print-help-message.js.map +0 -1
  161. package/lib/commonjs/help-message/print-options.js +0 -1
  162. package/lib/commonjs/help-message/print-options.js.map +0 -1
  163. package/lib/commonjs/help-message/print-subcommands.js +0 -1
  164. package/lib/commonjs/help-message/print-subcommands.js.map +0 -1
  165. package/lib/commonjs/help-message/utils.js +0 -1
  166. package/lib/commonjs/help-message/utils.js.map +0 -1
  167. package/lib/commonjs/parser/parse.js +0 -1
  168. package/lib/commonjs/parser/parse.js.map +0 -1
  169. package/lib/commonjs/zodUtils.js +0 -1
  170. package/lib/commonjs/zodUtils.js.map +0 -1
  171. package/lib/module/help-message/colors.js +0 -1
  172. package/lib/module/help-message/colors.js.map +0 -1
  173. package/lib/module/help-message/print-arguments.js +0 -1
  174. package/lib/module/help-message/print-arguments.js.map +0 -1
  175. package/lib/module/help-message/print-help-message.js +0 -1
  176. package/lib/module/help-message/print-help-message.js.map +0 -1
  177. package/lib/module/help-message/print-options.js +0 -1
  178. package/lib/module/help-message/print-options.js.map +0 -1
  179. package/lib/module/help-message/print-subcommands.js.map +0 -1
  180. package/lib/module/help-message/utils.js +0 -1
  181. package/lib/module/help-message/utils.js.map +0 -1
  182. package/lib/module/parser/parse.js +0 -1
  183. package/lib/module/parser/parse.js.map +0 -1
  184. package/lib/module/zodUtils.js +0 -1
  185. package/lib/module/zodUtils.js.map +0 -1
  186. package/lib/typescript/help-message/colors.d.ts +0 -17
  187. package/lib/typescript/help-message/colors.d.ts.map +0 -1
  188. package/lib/typescript/help-message/print-arguments.d.ts +0 -4
  189. package/lib/typescript/help-message/print-arguments.d.ts.map +0 -1
  190. package/lib/typescript/help-message/print-help-message.d.ts +0 -4
  191. package/lib/typescript/help-message/print-help-message.d.ts.map +0 -1
  192. package/lib/typescript/help-message/print-options.d.ts +0 -4
  193. package/lib/typescript/help-message/print-options.d.ts.map +0 -1
  194. package/lib/typescript/help-message/print-subcommands.d.ts +0 -4
  195. package/lib/typescript/help-message/print-subcommands.d.ts.map +0 -1
  196. package/lib/typescript/help-message/utils.d.ts +0 -13
  197. package/lib/typescript/help-message/utils.d.ts.map +0 -1
  198. package/lib/typescript/parser/parse.d.ts +0 -3
  199. package/lib/typescript/parser/parse.d.ts.map +0 -1
  200. package/lib/typescript/zodUtils.d.ts +0 -14
  201. package/lib/typescript/zodUtils.d.ts.map +0 -1
  202. package/src/help-message/colors.ts +0 -24
  203. package/src/help-message/print-arguments.ts +0 -35
  204. package/src/help-message/print-subcommands.ts +0 -28
  205. package/src/help-message/utils.ts +0 -31
  206. package/src/parser/parse.ts +0 -272
package/README.md CHANGED
@@ -1,6 +1,31 @@
1
1
  # zod-args-parser
2
2
 
3
- A strictly typed command-line arguments parser powered by Zod.
3
+ [![npm](https://img.shields.io/npm/v/zod-args-parser?style=for-the-badge)](https://www.npmjs.com/package/zod-args-parser)
4
+ [![GitHub](https://img.shields.io/github/license/alabsi91/zod-args-parser?style=for-the-badge)](https://github.com/alabsi91/zod-args-parser/blob/main/LICENSE)
5
+ [![GitHub issues](https://img.shields.io/github/issues/alabsi91/zod-args-parser?style=for-the-badge)](https://github.com/alabsi91/zod-args-parser/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
6
+
7
+ A strictly typed command-line arguments parser powered by [Zod](https://github.com/colinhacks/zod).
8
+
9
+ ## Table of Contents
10
+
11
+ - [Features](#features)
12
+ - [Installation](#installation)
13
+ - [Usage](#usage)
14
+ - [Guid](#guid)
15
+ - [Subcommands](#subcommands)
16
+ - [Type Zod Schemas](#type-zod-schemas)
17
+ - [Options](#options)
18
+ - [Arguments](#arguments)
19
+ - [Positionals](#positionals)
20
+ - [Pre-Validation Hook](#pre-validation-hook)
21
+ - [Help Message](#help-message)
22
+ - [Zod Utilities](#zod-utilities)
23
+ - [Type Utilities](#type-utilities)
24
+ - [API Reference](#api-reference)
25
+ - [Methods](#methods)
26
+ - [Types](#types)
27
+ - [Example](#example)
28
+ - [License](#license)
4
29
 
5
30
  ## Features
6
31
 
@@ -9,6 +34,8 @@ A strictly typed command-line arguments parser powered by Zod.
9
34
  - **Negative flag support**: e.g., `--no-verbose` to negate `--verbose`.
10
35
  - **Flexible option value formatting**: Supports both `--input-dir path` and `--input-dir=path` styles.
11
36
  - **Help message generation**: Built-in methods to generate help text for the CLI and each subcommand.
37
+ - **Auto completion**: Generate shell (bash, zsh, powershell) completion scripts for your CLI.
38
+ - **Documentation**: Generate a markdown documentation for your CLI.
12
39
 
13
40
  ## Installation
14
41
 
@@ -22,10 +49,10 @@ npm install zod chalk zod-args-parser
22
49
  ## Usage
23
50
 
24
51
  ```ts
25
- import { z } from "zod";
52
+ import * as z from "zod";
26
53
  import { createCli, createSubcommand, createOptions, safeParse } from "zod-args-parser";
27
54
 
28
- // Share same options between subcommands
55
+ // Share options between schemas.
29
56
  const sharedOptions = createOptions([
30
57
  {
31
58
  name: "verbose",
@@ -34,8 +61,8 @@ const sharedOptions = createOptions([
34
61
  },
35
62
  ]);
36
63
 
37
- // Create a CLI schema
38
- // This will be used when no subcommands are provided
64
+ // Create the CLI program schema
65
+ // This will be used when no subcommands are run
39
66
  const cliSchema = createCli({
40
67
  cliName: "my-cli",
41
68
  description: "A description for my CLI",
@@ -92,16 +119,17 @@ const helpCommandSchema = createSubcommand({
92
119
  // Execute this function when the `help` subcommand is run
93
120
  helpCommandSchema.setAction(results => {
94
121
  const [command] = results.arguments;
95
- if (command) results.printSubcommandHelp(command);
96
- else results.printCliHelp();
122
+ if (command) {
123
+ results.printSubcommandHelp(command);
124
+ return;
125
+ }
126
+
127
+ results.printCliHelp();
97
128
  });
98
129
 
99
- const results = safeParse(
100
- process.argv.slice(2),
101
- cliSchema,
102
- helpCommandSchema,
103
- // Add more subcommands
104
- );
130
+ const schemas = [cliSchema, helpCommandSchema /* Add more subcommands */] as const;
131
+
132
+ const results = safeParse(process.argv.slice(2), ...schemas);
105
133
 
106
134
  // ! Error
107
135
  if (!results.success) {
@@ -111,7 +139,387 @@ if (!results.success) {
111
139
  }
112
140
  ```
113
141
 
114
- ## Types Utility
142
+ ## Guid
143
+
144
+ ### Subcommands
145
+
146
+ - Subcommands are defined using the `createSubcommand` function, which accepts an object with the type [`Subcommand`](#subcommand).
147
+ - The following properties are optional and used only for **metadata** such as help messages and documentation:
148
+ - `description`
149
+ - `usage`
150
+ - `example`
151
+ - `placeholder`
152
+ - Do not reuse the same subcommand name within the same CLI. TypeScript will throw a type error if a duplicate exist.
153
+
154
+ ```ts
155
+ import { createSubcommand } from "zod-args-parser";
156
+
157
+ const subcommand = createSubcommand({
158
+ name: "subcommand",
159
+ description: "Description for the subcommand",
160
+ usage: "my-cli subcommand [options] [arguments]",
161
+ example: "subcommand --help",
162
+ placeholder: "[options] [arguments]",
163
+ allowPositional: false, // default: false
164
+ options: [
165
+ /* options */
166
+ ],
167
+ arguments: [
168
+ /* arguments */
169
+ ],
170
+ });
171
+
172
+ // Executed when the subcommand is run after parsing before validation
173
+ subcommand.setPreValidationHook(ctx => {
174
+ // ...
175
+ });
176
+
177
+ // Executed when the subcommand is run
178
+ subcommand.setAction(results => {
179
+ // ...
180
+ });
181
+ ```
182
+
183
+ ### Type Zod Schemas
184
+
185
+ - A schema with `.optional()` or `.default(<value>)` is treated as **optional**; all others are **required**.
186
+ - Descriptions can be added either via the Zod schema’s `describe` method or the `description` property.
187
+
188
+ > [!IMPORTANT]
189
+ > All values from the terminal are passed as **strings**, so **coercion** is required except for simple booleans types which are inferred automatically.
190
+
191
+ ```ts
192
+ import * as z from "zod";
193
+
194
+ // String examples
195
+ z.string(); // required -> string
196
+ z.string().optional(); // optional -> string | undefined
197
+ z.string().default("hello"); // optional -> string
198
+
199
+ // Boolean examples (simple booleans are inferred automatically no need to use coerce)
200
+ z.boolean(); // required -> boolean
201
+ z.boolean().optional(); // optional -> boolean | undefined
202
+ z.boolean().default(true); // optional -> boolean
203
+
204
+ // Number examples (need coercion because terminal inputs are strings)
205
+ z.number(); // 🚫 invalid: will always throw
206
+ z.coerce.number(); // ✅ converts string input -> number
207
+
208
+ // String boolean (zod v4) -> boolean
209
+ z.stringbool({
210
+ truthy: ["true", "1", "yes", "on", "y", "enabled"],
211
+ falsy: ["false", "0", "no", "off", "n", "disabled"],
212
+ });
213
+
214
+ // Enum -> "a" | "b" | "c"
215
+ z.enum(["a", "b", "c"]);
216
+
217
+ // Union -> number | "development"
218
+ z.union([z.coerce.number(), z.literal("development")]);
219
+
220
+ // Custom preprocessing:
221
+ import { stringToArray, stringToSet } from "zod-args-parser";
222
+
223
+ // Array -> string[]
224
+ z.preprocess(val => stringToArray(val), z.string().array());
225
+
226
+ // Tuple -> [string, number, boolean]
227
+ z.preprocess(
228
+ val => stringToArray(val, ";"), // second arg is the separator (default: ",")
229
+ z.tuple([z.string(), z.coerce.number(), z.coerce.boolean()]),
230
+ );
231
+
232
+ // Set -> Set<string>
233
+ z.preprocess(val => stringToSet(val), z.set(z.string()));
234
+ ```
235
+
236
+ ### Options
237
+
238
+ - Option names and aliases must use a valid **JavaScript** variable name.
239
+ - **Supports:** `camelCase`, `PascalCase`, `snake_case`, and `SCREAMING_SNAKE_CASE`.
240
+ - **Examples:**
241
+ - `I` or `i` ➡️ `-i`
242
+ - `InputDir`, `inputDir`, or `INPUT_DIR` ➡️ `--input-dir`
243
+ - `Help`, `help`, or `HELP` ➡️ `--help`
244
+ - Do not use same options/aliases name with different casing.
245
+ - Do not reuse the option/alias name within the same CLI/subcommand. TypeScript will throw a type error if duplicates exist.
246
+ - The following properties are optional and used only for **metadata** such as help messages and documentation:
247
+ - `description`
248
+ - `example`
249
+ - `placeholder`
250
+
251
+ See the [Option](#option) type for more details.
252
+
253
+ ```ts
254
+ import * as z from "zod";
255
+ import { createCli } from "zod-args-parser";
256
+
257
+ // Define the CLI schema
258
+ const cliSchema = createCli({
259
+ cliName: "my-cli",
260
+ options: [
261
+ {
262
+ name: "inputDir", // camelCase option name becomes `--input-dir`
263
+ aliases: ["i"], // single-letter alias becomes `-i`
264
+ type: z.boolean().default(false), // optional because of default
265
+ description: "Input directory",
266
+ placeholder: "<dir>",
267
+ example: "-i /path/to/dir",
268
+ },
269
+ {
270
+ name: "verbose", // another option
271
+ aliases: ["v"], // alias `-v`
272
+ type: z.boolean().optional().describe("Enable verbose mode"), // using describe() instead of description
273
+ },
274
+ ],
275
+ });
276
+
277
+ // Define the CLI action
278
+ cliSchema.setAction(results => {
279
+ const { inputDir, verbose } = results.options;
280
+
281
+ // inputDir: boolean (optional, with default = false)
282
+ // verbose: boolean | undefined (optional, no default)
283
+ });
284
+ ```
285
+
286
+ ### Arguments
287
+
288
+ - Arguments are strictly typed **positional values**, defined as a tuple: `[arg1, arg2, arg3]`.
289
+ - Each argument must have a **name**, which is used for help messages and documentation. TypeScript will throw a type error if duplicates name exist within the same CLI/subcommand.
290
+ - The following properties are optional and used only for **metadata**:
291
+ - `description`
292
+ - `example`
293
+
294
+ > [!IMPORTANT]
295
+ > Arguments are parsed strictly **in order**.
296
+ >
297
+ > - Only the **last argument** may be optional (when `allowPositional` is disabled).
298
+ > - Mixing required and optional arguments (e.g., required → optional → required) will cause parsing errors because the parser cannot determine which value belongs to which argument.
299
+ > - This means you **cannot have any optional arguments** if `allowPositional` is enabled.
300
+ > - TypeScript will throw a type error if required and optional arguments are mixed, or when using `allowPositional: true` with optional arguments.
301
+
302
+ See the [Argument](#argument) type for more details.
303
+
304
+ ```ts
305
+ import * as z from "zod";
306
+ import { createCli } from "zod-args-parser";
307
+
308
+ // Define the CLI schema
309
+ const cliSchema = createCli({
310
+ cliName: "my-cli",
311
+ arguments: [
312
+ {
313
+ name: "inputFile", // argument name (camelCase for consistency)
314
+ type: z.string(), // required
315
+ description: "Input file",
316
+ example: "input.txt",
317
+ },
318
+ {
319
+ name: "outputFile", // second argument
320
+ type: z.string().optional(), // optional (only allowed as the last arg)
321
+ description: "Output file",
322
+ example: "output.txt",
323
+ },
324
+ ],
325
+ });
326
+
327
+ // Define the CLI action
328
+ cliSchema.setAction(results => {
329
+ const [inputFile, outputFile] = results.arguments;
330
+
331
+ // inputFile: string (required)
332
+ // outputFile: string | undefined (optional, no default)
333
+ });
334
+ ```
335
+
336
+ ### Positionals
337
+
338
+ - Positionals are untyped **positional values**, always parsed as `string[]` of any length.
339
+ - By default, positionals are **not allowed**. Enable them using the `allowPositional` option.
340
+
341
+ > [!IMPORTANT]
342
+ > If both typed arguments and positionals are used in the same CLI/subcommand, the **typed arguments are parsed first**, and only then are the remaining values collected as positionals.
343
+
344
+ ```ts
345
+ import { createSubcommand } from "zod-args-parser";
346
+
347
+ // Define the subcommand schema
348
+ export const countSchema = createSubcommand({
349
+ name: "count",
350
+ aliases: ["list"],
351
+ description: "Print a list of items provided by the user",
352
+ allowPositional: true, // enable positionals
353
+ });
354
+
355
+ // Define the subcommand action
356
+ countSchema.setAction(results => {
357
+ const items = results.positional; // string[]
358
+
359
+ if (items.length === 0) {
360
+ console.log("No items provided");
361
+ return;
362
+ }
363
+
364
+ console.log("-- List of items --\n -", items.join("\n - "));
365
+ });
366
+ ```
367
+
368
+ ### Pre-Validation Hook
369
+
370
+ - The `preValidationHook` is called after parsing but before validation.
371
+ - The provided context object can be modified before validation for advanced use cases.
372
+ - When using **async** hooks, make sure to call [`parseAsync`](#parseasync) or [`safeParseAsync`](#parseasync).
373
+
374
+ See the [Context](#context) type for more details.
375
+
376
+ ```ts
377
+ import * as z from "zod";
378
+ import { createCli } from "zod-args-parser";
379
+
380
+ // Define the CLI schema
381
+ const cliSchema = createCli({
382
+ cliName: "my-cli",
383
+ options: [
384
+ { name: "inputDir", type: z.string() },
385
+ { name: "verbose", type: z.boolean().default(false) },
386
+ ],
387
+ arguments: [
388
+ { name: "first-argument", type: z.string() },
389
+ { name: "second-argument", type: z.string().optional() },
390
+ ],
391
+ });
392
+
393
+ // Define the pre-validation hook
394
+ cliSchema.setPreValidationHook(ctx => {
395
+ if (ctx.options.verbose.source === "default") {
396
+ ctx.options.verbose.rawValue = "true";
397
+ }
398
+
399
+ if (ctx.arguments[0].source === "cli") {
400
+ console.log("first-argument:", ctx.arguments[0].rawValue);
401
+ }
402
+ });
403
+
404
+ // Define the CLI action
405
+ cliSchema.setAction(results => {
406
+ // can access `ctx` here
407
+ console.log(results.ctx.options.verbose);
408
+ });
409
+ ```
410
+
411
+ ### Help Message
412
+
413
+ Cli help message example preview
414
+
415
+ <img width="1153" height="682" alt="image" src="https://github.com/user-attachments/assets/5610e5d0-8c08-4776-bbfc-b8e655241c39" /><br>
416
+
417
+ Subcommand help message example preview
418
+
419
+ <img width="1115" height="522" alt="image" src="https://github.com/user-attachments/assets/2a56a549-4059-45c4-84d2-93adaedaaac8" /><br>
420
+
421
+ There are two ways to print the help message:
422
+
423
+ 1. `printCliHelp(style?: HelpMsgStyle)`
424
+ Print the help message for the CLI.
425
+
426
+ 2. `printSubcommandHelp(subcommandName: string, style?: HelpMsgStyle)`
427
+ Print the help message for a specific subcommand.
428
+
429
+ See the [HelpMsgStyle](#helpmsgstyle) type for more details.
430
+
431
+ ```ts
432
+ import chalk from "chalk";
433
+ import { formatCliHelpMsg, formatSubcommandHelpMsg, helpMsgStyles } from "zod-args-parser";
434
+
435
+ // Define the CLI schema
436
+ const cliSchema = createCli(/* ... */);
437
+
438
+ // Define the subcommand schema
439
+ const subcommandSchema = createSubcommand(/* ... */);
440
+
441
+ subcommandSchema.setAction(results => {
442
+ // print help for CLI (without colors)
443
+ results.printCliHelp(helpMsgStyles.noColors);
444
+
445
+ // choose a style
446
+ results.printCliHelp(helpMsgStyles.dracula);
447
+
448
+ // print help for subcommand (with custom title color)
449
+ results.printSubcommandHelp("build", { title: chalk.red });
450
+ });
451
+
452
+ const schemas = [cliSchema, subcommandSchema] as const;
453
+
454
+ // print help functions also accessible here
455
+ const results = safeParse(args, ...schemas);
456
+ if (results.success) {
457
+ results.printCliHelp();
458
+ }
459
+
460
+ // get the string without printing to console
461
+ const cliHelp = formatCliHelpMsg(schemas, helpMsgStyles.html);
462
+ console.log(`<pre style="background-color: #1e1e2e">${cliHelp}</pre>`);
463
+
464
+ const subcommandHelp = formatSubcommandHelpMsg(subcommandSchema, helpMsgStyles.html, cliSchema.cliName);
465
+ console.log(`<pre style="background-color: #1e1e2e">${subcommandHelp}</pre>`);
466
+ ```
467
+
468
+ ### Zod Utilities
469
+
470
+ - `isOptionalSchema(schema: ZodTypeAny): boolean`
471
+ Check if a schema is optional or has a default value.
472
+
473
+ - `schemaDefaultValue(schema: ZodTypeAny): unknown | undefined`
474
+ Get the default value of a schema if it has one.
475
+
476
+ - `stringToArray(value: unknown, separator?: string = ","): unknown`
477
+ A preprocessing handle to convert a string to an array.
478
+
479
+ - `stringToSet(value: unknown, separator?: string = ","): unknown`
480
+ A preprocessing handle to convert a string to a set.
481
+
482
+ ```ts
483
+ import * as z from "zod";
484
+ import { createCli, isOptionalSchema, schemaDefaultValue, stringToArray } from "zod-args-parser";
485
+
486
+ const cliSchema = createCli({
487
+ cliName: "my-cli",
488
+ options: [
489
+ {
490
+ name: "tags",
491
+ aliases: ["t"],
492
+ placeholder: "<list>",
493
+ description: "tags separated by semicolon (;)",
494
+ example: "--tags tag1;tag2;tag3",
495
+ type: z.preprocess(val => stringToArray(val, ";"), z.array(z.string())),
496
+ },
497
+ {
498
+ name: "verbose",
499
+ aliases: ["v"],
500
+ description: "Verbose mode",
501
+ type: z.boolean().default(false),
502
+ },
503
+ ],
504
+ });
505
+
506
+ cliSchema.setAction(results => {
507
+ const ctxOptions = results.ctx.options;
508
+
509
+ console.log(
510
+ isOptionalSchema(ctxOptions.verbose.schema), // true
511
+ schemaDefaultValue(ctxOptions.verbose.schema), // false
512
+ );
513
+ });
514
+ ```
515
+
516
+ ### Type Utilities
517
+
518
+ - `InferOptionsType<Cli | Subcommand>`
519
+ Infer the options type from the Cli or subcommand schema.
520
+
521
+ - `InferArgumentsType<Cli | Subcommand>`
522
+ Infer the arguments type from the Cli or subcommand schema.
115
523
 
116
524
  ```ts
117
525
  import { createSubcommand } from "zod-args-parser";
@@ -139,122 +547,220 @@ type Arguments = InferArgumentsType<typeof subcommand>;
139
547
  // [string, number, boolean]
140
548
  ```
141
549
 
142
- ## API
550
+ ## API Reference
143
551
 
144
- ### `Subcommand`
552
+ ### Methods
145
553
 
146
- - `name: string`
147
- The name of the subcommand.
554
+ #### createCli
148
555
 
149
- - `aliases?: string[]`
150
- An array of aliases for the subcommand.
556
+ `(schema: Cli) => Cli & SetMethods<Cli>`
151
557
 
152
- - `description?: string`
153
- A description of the subcommand for the help message.
558
+ Creates the CLI program schema.
154
559
 
155
- - `usage?: string`
156
- The usage of the subcommand for the help message.
560
+ See [Cli](#cli) object type.
157
561
 
158
- - `placeholder?: string`
159
- A placeholder displayed in the help message alongside the subcommand name.
562
+ #### createSubcommand
160
563
 
161
- - `example?: string`
162
- An example of subcommand usage for the help message.
564
+ `(schema: Subcommand) => Subcommand & SetMethods<Subcommand>`
163
565
 
164
- - `allowPositional?: boolean`
165
- Allows positional arguments for this subcommand.
166
- Positional arguments are untyped (`string[]`) when enabled with the typed `arguments` any extra arguments, beyond the typed `arguments`, are parsed as positional and stored in the `positional` property.
566
+ Creates the subcommand schema.
167
567
 
168
- - `options?: Option[]`
169
- An array of options for the subcommand.
568
+ See [Subcommand](#subcommand) object type.
170
569
 
171
- - `name: string`
172
- The name of the option. camelCase is recommended. E.g. `inputDir` -> `--input-dir`
570
+ #### createOptions
173
571
 
174
- - `aliases?: string[]`
175
- An array of aliases for the option.
572
+ `(schema: Option[]) => Option[]`
176
573
 
177
- - `type: ZodType`
178
- Specifies the type of the option using Zod.
574
+ Creates an array of option schemas for option sharing.
179
575
 
180
- **Examples:**
576
+ See [Option](#option) object type.
181
577
 
182
- - `type: z.boolean().default(false);`
183
- - `type: z.coerce.number(); // coerces value to a number`
184
- - `type: z.preprocess(parseStringToArrFn, z.array(z.coerce.number())); // array of numbers`
578
+ #### createArguments
185
579
 
186
- - `description?: string`
187
- A description of the option for the help message.
580
+ `(schema: Argument[]) => Argument[]`
188
581
 
189
- - `placeholder?: string`
190
- Placeholder text for the option in the help message.
582
+ Creates an array of argument schemas for argument sharing.
191
583
 
192
- - `example?: string`
193
- An example of option usage for the help message.
584
+ See [Argument](#argument) object type.
194
585
 
195
- - `arguments?: Argument[]`
196
- An array of arguments for the subcommand.
586
+ #### parse
197
587
 
198
- - `name: string`
199
- The name of the argument for display in the help message.
588
+ `(args: string[], cli: Cli, ...subcommands: Subcommand[]) => Result`
200
589
 
201
- - `type: ZodType`
202
- Specifies the type of the argument using Zod.
590
+ Parses and validates the provided arguments and throws an error if parsing or validation failed.
203
591
 
204
- **Examples:**
592
+ See [Cli](#cli), [Subcommand](#subcommand), and [Results](#results)
205
593
 
206
- - `type: z.boolean();`
207
- - `type: z.coerce.number(); // coerces value to a number`
594
+ #### parseAsync
208
595
 
209
- - `description?: string`
210
- A description of the argument for the help message.
596
+ `(args: string[], cli: Cli, ...subcommands: Subcommand[]) => Promise<Result>`
211
597
 
212
- - `example?: string`
213
- An example of argument usage for the help message.
598
+ Same as [`parse`](#parse), but returns a promise.
599
+ Use this when you have async actions or hooks.
214
600
 
215
- ### Results
601
+ See [Cli](#cli), [Subcommand](#subcommand), and [Results](#results)
216
602
 
217
- - `subcommand: string | undefined`
218
- The name of the executed subcommand.
219
- If no subcommand is executed, this will be `undefined`.
603
+ #### safeParse
220
604
 
221
- - `arguments?: any[]`
222
- An array representing defined arguments for the subcommand, e.g., `[string, number]`.
223
- Only defined if the subcommand has specified `arguments`.
605
+ `(args: string[], cli: Cli, ...subcommands: Subcommand[]) => { success: false, error: Error } | { success: true, data: Result }`
224
606
 
225
- - `positional?: string[]`
226
- Contains positional arguments as `string[]` if `allowPositional` is enabled for the subcommand.
607
+ Parses and validates the provided arguments without throwing an error.
227
608
 
228
- - `printCliHelp(options?: PrintHelpOpt): void`
229
- Prints the CLI help message.
230
- Accepts an optional `options` object to disable colors or customize colors.
609
+ See [Cli](#cli), [Subcommand](#subcommand), and [Results](#results)
231
610
 
232
- - `printSubcommandHelp(subcommand: string, options?: PrintHelpOpt): void`
233
- Prints the help message for a specified subcommand.
611
+ #### safeParseAsync
234
612
 
235
- - `[key: optionName]: optionType`
236
- Represents options specified in the CLI or subcommand with their respective types.
613
+ `(args: string[], cli: Cli, ...subcommands: Subcommand[]) => Promise<...>`
237
614
 
238
- ### `parse(args: string[], cli: Cli, ...subcommands: Subcommand[]): UnSafeParseResult`
615
+ Same as [`safeParse`](#safeparse), but returns a promise.
616
+ Use this when you have async actions or hooks.
239
617
 
240
- Parses the provided arguments and returns a `Results` object.
241
- Throws an error if parsing fails.
618
+ See [Cli](#cli), [Subcommand](#subcommand), and [Results](#results)
242
619
 
243
- ### `safeParse(args: string[], cli: Cli, ...subcommands: Subcommand[]): SafeParseResult`
620
+ #### generateBashAutocompleteScript
244
621
 
245
- Parses the provided arguments and returns:
622
+ `(...params: [Cli, ...Subcommand[]]) => string`
246
623
 
247
- ```ts
248
- { success: false, error: Error } | { success: true, data: ResultObj }
249
- ```
624
+ Generates an autocomplete script for `bash`.
625
+
626
+ See [Cli](#cli) and [Subcommand](#subcommand)
627
+
628
+ #### generatePowerShellAutocompleteScript
629
+
630
+ `(...params: [Cli, ...Subcommand[]]) => string`
631
+
632
+ Generates an autocomplete script for `powershell`.
633
+
634
+ See [Cli](#cli) and [Subcommand](#subcommand)
635
+
636
+ #### generateZshAutocompleteScript
250
637
 
251
- ## Extras
638
+ `(...params: [Cli, ...Subcommand[]]) => string`
252
639
 
253
- - `generateBashAutocompleteScript(...params: [Cli, ...Subcommand[]]): string`
254
- - `generatePowerShellAutocompleteScript(...params: [Cli, ...Subcommand[]]): string`
255
- - `generateZshAutocompleteScript(...params: [Cli, ...Subcommand[]]): string`
256
- - `generateMarkdown(...params: [Cli, ...Subcommand[]]): string`
640
+ Generates an autocomplete script for `zsh`.
641
+
642
+ See [Cli](#cli) and [Subcommand](#subcommand)
643
+
644
+ #### generateMarkdown
645
+
646
+ `(...params: [Cli, ...Subcommand[]]) => string`
647
+
648
+ Generates a markdown documentation for your CLI.
649
+
650
+ See [Cli](#cli) and [Subcommand](#subcommand)
651
+
652
+ ### Types
653
+
654
+ #### Cli
655
+
656
+ | Name | Type | Description | Example |
657
+ | --------------- | -------------------------- | ---------------------------------------------- | ------------------------------ |
658
+ | cliName | `string` | The name of the CLI program. | `"my-cli"` |
659
+ | description | `string?` | A description of the CLI for the help message. | `"Build the project"` |
660
+ | usage | `string?` | The usage of the CLI for the help message. | `"my-cli build"` |
661
+ | example | `string?` | An example of CLI usage for the help message. | `"my-cli <command> [options]"` |
662
+ | options | [`Option[]?`](#option) | An array of options for the CLI. | |
663
+ | arguments | [`Argument[]?`](#argument) | An array of arguments for the CLI. | |
664
+ | allowPositional | `boolean?` | Allows positional arguments for the CLI. | |
665
+
666
+ #### Subcommand
667
+
668
+ | Name | Type | Description | Example |
669
+ | --------------- | -------------------------- | ----------------------------------------------------- | -------------------------- |
670
+ | name | `string` | The name of the subcommand. | `"build"` |
671
+ | aliases | `string[]?` | An array of aliases for the subcommand. | `["b", "build"]` |
672
+ | description | `string?` | A description of the subcommand for the help message. | `"Build the project"` |
673
+ | usage | `string?` | The usage of the subcommand for the help message. | `"my-cli build"` |
674
+ | placeholder | `string?` | A placeholder displayed in the help message. | `"[options]"` |
675
+ | example | `string?` | An example of subcommand usage for the help message. | `"my-cli build [options]"` |
676
+ | options | [`Option[]?`](#option) | An array of options for the subcommand. | |
677
+ | arguments | [`Argument[]?`](#argument) | An array of arguments for the subcommand. | |
678
+ | allowPositional | `boolean?` | Allows positional arguments for this subcommand. | |
679
+
680
+ #### Option
681
+
682
+ | Name | Type | Description | Example |
683
+ | ----------- | ----------- | ---------------------------------------------------- | ------------------------------- |
684
+ | name | `string` | The name of the option. camelCase is recommended. | `"inputDir"` -> `--input-dir` |
685
+ | type | `ZodType` | Specifies the type of the option using Zod schema. | `z.boolean().default(false)` |
686
+ | aliases | `string[]?` | An array of aliases for the option. | `["i", "dir"]` -> `-i`, `--dir` |
687
+ | description | `string?` | A description of the option for the help message. | `"Input directory"` |
688
+ | placeholder | `string?` | Placeholder text for the option in the help message. | `"<dir>"` or `"<path>"` |
689
+ | example | `string?` | An example of option usage for the help message. | `"-i /path/to/dir"` |
690
+
691
+ #### Argument
692
+
693
+ | Name | Type | Description | Example |
694
+ | ----------- | --------- | ---------------------------------------------------- | ----------------------------------- |
695
+ | name | `string` | The name of the argument for the help message. | `"command-name"` |
696
+ | type | `ZodType` | Specifies the type of the argument using Zod schema. | `z.enum(["build", "help", "init"])` |
697
+ | description | `string?` | A description of the argument for the help message. | `"Command to print help for"` |
698
+ | example | `string?` | An example of argument usage for the help message. | `"help build"` |
699
+
700
+ #### Context
701
+
702
+ The context object is generated after parsing the CLI arguments and before validation.
703
+
704
+ | Name | Type | Description |
705
+ | ---------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------- |
706
+ | subcommand | `string \| undefined` | The name of the executed subcommand. |
707
+ | options | `{ [OptionName: string]: ParsedOption }` | A map of parsed options for the CLI/subcommand. |
708
+ | arguments | `ParsedArgument[] \| undefined` | An array of parsed arguments for the CLI/subcommand. See [`ParsedArgument`](#parsedargument) |
709
+ | positional | `string[] \| undefined` | Contains positional arguments when `allowPositional` is enabled. See [`ParsedArgument`](#parsedargument) |
710
+
711
+ ##### ParsedOption
712
+
713
+ | Name | Type | Description |
714
+ | -------- | --------------------- | ---------------------------------------------------------------------------------------------- |
715
+ | name | `string` | The name of the option (e.g. `foo` or `f`). |
716
+ | flag | `string \| undefined` | The CLI flag as provided in the terminal (e.g. `--foo` or `-f`). |
717
+ | schema | `ZodTypeAny` | The schema that validates this option. |
718
+ | rawValue | `string \| undefined` | The string value as provided in the terminal. boolean flags are inferred into boolean strings. |
719
+ | source | `"cli" \| "default"` | `cli`: provided explicitly in the CLI, `default`: not provided, and the schema has a default. |
720
+
721
+ ##### ParsedArgument
722
+
723
+ | Name | Type | Description |
724
+ | -------- | --------------------- | --------------------------------------------------------------------------------------------- |
725
+ | schema | `ZodTypeAny` | The schema that validates this argument. |
726
+ | rawValue | `string \| undefined` | The raw string value supplied for this argument from the CLI. |
727
+ | source | `"cli" \| "default"` | `cli`: provided explicitly in the CLI, `default`: not provided, and the schema has a default. |
728
+
729
+ #### Results
730
+
731
+ | Name | Type | Description |
732
+ | ---------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------- |
733
+ | subcommand | `string \| undefined` | The name of the executed subcommand. |
734
+ | `[optionName: string]` | `unknown` | Validated options for the CLI/subcommand. |
735
+ | arguments | `unknown[] \| undefined` | Validated arguments for the CLI/subcommand. |
736
+ | positional | `string[] \| undefined` | Positional array for the CLI/subcommand. |
737
+ | printCliHelp | `(style?: HelpMsgStyle) => void` | Prints the CLI help message. See [HelpMsgStyle](#helpmsgstyle) |
738
+ | printSubcommandHelp | `(subcommand: string, style?: HelpMsgStyle) => void` | Prints the help message for a specified subcommand. See [HelpMsgStyle](#helpmsgstyle) |
739
+
740
+ #### HelpMsgStyle
741
+
742
+ Available styles: `default`, `dracula`, `solarizedDark`, `nord`, `html`, `gruvboxDark`, `monokai`, `oneDark`, `noColors`
743
+
744
+ Each style has the following properties:
745
+
746
+ | Key | Type | Default |
747
+ | ------------ | -------------------------------- | ---------------------- |
748
+ | title | `(...text: unknown[]) => string` | `chalk.bold.blue` |
749
+ | description | `(...text: unknown[]) => string` | `chalk.white` |
750
+ | default | `(...text: unknown[]) => string` | `chalk.dim.italic` |
751
+ | optional | `(...text: unknown[]) => string` | `chalk.dim.italic` |
752
+ | exampleTitle | `(...text: unknown[]) => string` | `chalk.yellow` |
753
+ | example | `(...text: unknown[]) => string` | `chalk.dim` |
754
+ | command | `(...text: unknown[]) => string` | `chalk.yellow` |
755
+ | option | `(...text: unknown[]) => string` | `chalk.cyan` |
756
+ | argument | `(...text: unknown[]) => string` | `chalk.green` |
757
+ | placeholder | `(...text: unknown[]) => string` | `chalk.hex("#FF9800")` |
758
+ | punctuation | `(...text: unknown[]) => string` | `chalk.white.dim` |
257
759
 
258
760
  ## Example
259
761
 
260
762
  - [Example code](https://github.com/alabsi91/zod-args-parser/tree/main/example)
763
+
764
+ ## License
765
+
766
+ **zod-args-parser** library is licensed under [**The MIT License.**](https://github.com/alabsi91/zod-args-parser/blob/main/LICENSE)