zod-args-parser 1.0.16 → 1.2.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 (200) hide show
  1. package/README.md +598 -92
  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 +76 -186
  124. package/lib/typescript/types.d.ts.map +1 -1
  125. package/lib/typescript/utils.d.ts +20 -23
  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 +20 -19
  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 +6 -5
  141. package/src/metadata/get-cli-metadata.ts +4 -4
  142. package/src/metadata/get-options-metadata.ts +7 -5
  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 +99 -233
  153. package/src/utils.ts +31 -96
  154. package/src/zod-utils.ts +199 -0
  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/module/help-message/colors.js +0 -1
  170. package/lib/module/help-message/colors.js.map +0 -1
  171. package/lib/module/help-message/print-arguments.js +0 -1
  172. package/lib/module/help-message/print-arguments.js.map +0 -1
  173. package/lib/module/help-message/print-help-message.js +0 -1
  174. package/lib/module/help-message/print-help-message.js.map +0 -1
  175. package/lib/module/help-message/print-options.js +0 -1
  176. package/lib/module/help-message/print-options.js.map +0 -1
  177. package/lib/module/help-message/print-subcommands.js.map +0 -1
  178. package/lib/module/help-message/utils.js +0 -1
  179. package/lib/module/help-message/utils.js.map +0 -1
  180. package/lib/module/parser/parse.js +0 -1
  181. package/lib/module/parser/parse.js.map +0 -1
  182. package/lib/typescript/help-message/colors.d.ts +0 -17
  183. package/lib/typescript/help-message/colors.d.ts.map +0 -1
  184. package/lib/typescript/help-message/print-arguments.d.ts +0 -4
  185. package/lib/typescript/help-message/print-arguments.d.ts.map +0 -1
  186. package/lib/typescript/help-message/print-help-message.d.ts +0 -4
  187. package/lib/typescript/help-message/print-help-message.d.ts.map +0 -1
  188. package/lib/typescript/help-message/print-options.d.ts +0 -4
  189. package/lib/typescript/help-message/print-options.d.ts.map +0 -1
  190. package/lib/typescript/help-message/print-subcommands.d.ts +0 -4
  191. package/lib/typescript/help-message/print-subcommands.d.ts.map +0 -1
  192. package/lib/typescript/help-message/utils.d.ts +0 -13
  193. package/lib/typescript/help-message/utils.d.ts.map +0 -1
  194. package/lib/typescript/parser/parse.d.ts +0 -3
  195. package/lib/typescript/parser/parse.d.ts.map +0 -1
  196. package/src/help-message/colors.ts +0 -24
  197. package/src/help-message/print-arguments.ts +0 -35
  198. package/src/help-message/print-subcommands.ts +0 -28
  199. package/src/help-message/utils.ts +0 -31
  200. package/src/parser/parse.ts +0 -270
@@ -0,0 +1,98 @@
1
+ import * as help from "../help-message/format-cli.js";
2
+ import { findSubcommand } from "./parse/parser-helpers.js";
3
+ import { validate } from "./validate/validate.js";
4
+ import { parse } from "./parse/parse.js";
5
+
6
+ import type { Cli, NoSubcommand, HelpMsgStyle, Subcommand, UnsafeParseResult } from "../types.js";
7
+
8
+ export function unsafeParse<T extends Subcommand[], U extends Cli>(
9
+ argv: string[],
10
+ ...params: [U, ...T]
11
+ ): UnsafeParseResult<[...T, NoSubcommand & U]> {
12
+ const cliOptions = ("cliName" in params[0] ? params[0] : {}) as U;
13
+ const subcommandArr = params as unknown as T;
14
+
15
+ // Parse
16
+ const parsedData = parse(argv, ...params);
17
+
18
+ const subcommandObj = findSubcommand(parsedData.subcommand, subcommandArr);
19
+ if (!subcommandObj) {
20
+ throw new Error(`Subcommand "${parsedData.subcommand}" does not exist`, { cause: "zod-args-parser" });
21
+ }
22
+
23
+ // Fire preValidation hook
24
+ if (subcommandObj.preValidation) {
25
+ subcommandObj.preValidation(parsedData);
26
+ }
27
+
28
+ // Validate
29
+ const validateResult = validate(parsedData);
30
+
31
+ Object.assign(validateResult, {
32
+ printCliHelp(style?: Partial<HelpMsgStyle>) {
33
+ help.printCliHelp(params, style);
34
+ },
35
+ printSubcommandHelp(subCmdName: string, style?: Partial<HelpMsgStyle>) {
36
+ const subcommandObj = findSubcommand(subCmdName, subcommandArr);
37
+ if (!subcommandObj) {
38
+ console.error(`Cannot print help for subcommand "${subCmdName}" as it does not exist`);
39
+ return;
40
+ }
41
+
42
+ help.printSubcommandHelp(subcommandObj, style, cliOptions.cliName);
43
+ },
44
+ });
45
+
46
+ // Fire action
47
+ if (subcommandObj.action) {
48
+ subcommandObj.action(validateResult);
49
+ }
50
+
51
+ return validateResult as UnsafeParseResult<[...T, NoSubcommand & U]>;
52
+ }
53
+
54
+ export async function unsafeParseAsync<T extends Subcommand[], U extends Cli>(
55
+ argv: string[],
56
+ ...params: [U, ...T]
57
+ ): Promise<UnsafeParseResult<[...T, NoSubcommand & U]>> {
58
+ const cliOptions = ("cliName" in params[0] ? params[0] : {}) as U;
59
+ const subcommandArr = params as unknown as T;
60
+
61
+ // Parse
62
+ const parsedData = parse(argv, ...params);
63
+
64
+ const subcommandObj = findSubcommand(parsedData.subcommand, subcommandArr);
65
+ if (!subcommandObj) {
66
+ throw new Error(`Subcommand "${parsedData.subcommand}" does not exist`, { cause: "zod-args-parser" });
67
+ }
68
+
69
+ // Fire preValidation hook
70
+ if (subcommandObj.preValidation) {
71
+ await subcommandObj.preValidation(parsedData);
72
+ }
73
+
74
+ // Validate
75
+ const validateResult = validate(parsedData);
76
+
77
+ Object.assign(validateResult, {
78
+ printCliHelp(style?: Partial<HelpMsgStyle>) {
79
+ help.printCliHelp(params, style);
80
+ },
81
+ printSubcommandHelp(subCmdName: string, style?: Partial<HelpMsgStyle>) {
82
+ const subcommandObj = findSubcommand(subCmdName, subcommandArr);
83
+ if (!subcommandObj) {
84
+ console.error(`Cannot print help for subcommand "${subCmdName}" as it does not exist`);
85
+ return;
86
+ }
87
+
88
+ help.printSubcommandHelp(subcommandObj, style, cliOptions.cliName);
89
+ },
90
+ });
91
+
92
+ // Fire action
93
+ if (subcommandObj.action) {
94
+ await subcommandObj.action(validateResult);
95
+ }
96
+
97
+ return validateResult as UnsafeParseResult<[...T, NoSubcommand & U]>;
98
+ }
@@ -0,0 +1,21 @@
1
+ import type { Argument, Option, Prettify, Schema, Subcommand, ToOptional, ZodInfer } from "../../types.js";
2
+ import type { ParseResult } from "../parse/parse-types.js";
3
+
4
+ type OptionsArr2RecordType<T extends Option[] | undefined> = T extends Option[]
5
+ ? ToOptional<{ [K in T[number]["name"]]: ZodInfer<Extract<T[number], { name: K }>["type"]> }>
6
+ : object;
7
+
8
+ type ArgumentsArr2ArrType<T extends Argument[] | undefined> = T extends Argument[]
9
+ ? { [K in keyof T]: T[K] extends { type: Schema } ? ZodInfer<T[K]["type"]> : never }
10
+ : never;
11
+
12
+ export type ValidateResult<S extends Partial<Subcommand>[]> = {
13
+ [K in keyof S]: Prettify<
14
+ {
15
+ subcommand: S[K]["name"] extends string ? S[K]["name"] : undefined;
16
+ arguments: ArgumentsArr2ArrType<S[K]["arguments"]>;
17
+ positional: S[K]["allowPositional"] extends true ? string[] : never;
18
+ ctx: ParseResult<S>;
19
+ } & OptionsArr2RecordType<S[K]["options"]>
20
+ >;
21
+ }[number];
@@ -0,0 +1,66 @@
1
+ import { prettifyError } from "zod/v4";
2
+
3
+ import { generateOrdinalSuffix, stringToBoolean } from "../../utils.js";
4
+ import { isBooleanSchema, safeParseSchema } from "../../zod-utils.js";
5
+
6
+ import type { ParseCtx } from "../parse/parse-types.js";
7
+
8
+ /** The return result object temporarily type. used inside the `parse` function */
9
+ type ResultsTempType = Record<string, unknown> & {
10
+ subcommand: string | undefined;
11
+ positional?: string[];
12
+ arguments?: unknown[];
13
+ ctx: ParseCtx;
14
+ };
15
+
16
+ export function validate(parsedData: ParseCtx) {
17
+ const results: ResultsTempType = {
18
+ subcommand: parsedData.subcommand,
19
+ positional: parsedData.positional,
20
+ ctx: parsedData,
21
+ };
22
+
23
+ // validate options
24
+ for (const [optionName, { schema, rawValue, flag }] of Object.entries(parsedData.options)) {
25
+ let optionsValue: string | boolean | undefined = rawValue;
26
+
27
+ // infer boolean value if possible
28
+ if (flag && rawValue && isBooleanSchema(schema)) {
29
+ const booleanValue = stringToBoolean(rawValue);
30
+ if (typeof booleanValue === "boolean") {
31
+ const isNegated = flag.startsWith("--no");
32
+ optionsValue = isNegated ? !booleanValue : booleanValue;
33
+ }
34
+ }
35
+
36
+ const res = safeParseSchema(schema, optionsValue);
37
+ if (!res.success) {
38
+ throw new Error(`Invalid value "${rawValue}" for "${flag}": ${prettifyError(res.error)}`, {
39
+ cause: "zod-args-parser",
40
+ });
41
+ }
42
+
43
+ results[optionName] = res.data;
44
+ }
45
+
46
+ // validate arguments
47
+ if (parsedData.arguments) {
48
+ if (!results.arguments) results.arguments = [];
49
+
50
+ for (const { schema, rawValue } of parsedData.arguments) {
51
+ const argValue = rawValue && isBooleanSchema(schema) ? stringToBoolean(rawValue) : rawValue;
52
+
53
+ const res = safeParseSchema(schema, argValue);
54
+ if (!res.success) {
55
+ throw new Error(
56
+ `The ${generateOrdinalSuffix(results.arguments.length)} argument "${rawValue}" is invalid: ${prettifyError(res.error)}`,
57
+ { cause: "zod-args-parser" },
58
+ );
59
+ }
60
+
61
+ results.arguments.push(res.data);
62
+ }
63
+ }
64
+
65
+ return results;
66
+ }
package/src/types.ts CHANGED
@@ -1,124 +1,17 @@
1
- import type { z } from "zod";
1
+ import type * as Z3 from "zod/v3";
2
+ import type * as Z4 from "zod/v4/core";
3
+ import type { ParseResult } from "./parser/parse/parse-types.js";
4
+ import type { ValidateResult } from "./parser/validate/validate-type.js";
2
5
 
3
- export interface CliMetadata {
4
- /** The name of the cli program. */
5
- readonly name: string;
6
+ export type SchemaV3 = Z3.ZodTypeAny;
7
+ export type SchemaV4 = Z4.$ZodType;
8
+ export type Schema = SchemaV3 | SchemaV4;
6
9
 
7
- /** - The description of the cli program. Empty string if not provided */
8
- readonly description: string;
9
-
10
- /** - The placeholder of the option. Empty string if not provided */
11
- readonly placeholder: string;
12
-
13
- /** - The usage of the cli program. Empty string if not provided */
14
- readonly usage: string;
15
-
16
- /** - The example of the cli program. Empty string if not provided */
17
- readonly example: string;
18
-
19
- /** - Whether the cli program allows positional arguments. */
20
- readonly allowPositional: boolean;
21
-
22
- /** - The options of the cli program. Empty array if not provided */
23
- readonly options: OptionMetadata[];
24
-
25
- /** - The arguments of the cli program. Empty array if not provided */
26
- readonly arguments: ArgumentMetadata[];
27
-
28
- /** - The subcommands of the cli program. Empty array if not provided */
29
- readonly subcommands: SubcommandMetadata[];
30
- }
31
-
32
- export interface SubcommandMetadata {
33
- /** The subcommand name. */
34
- readonly name: string;
35
-
36
- /** - The aliases of the subcommand. Empty array if not provided */
37
- readonly aliases: string[];
38
-
39
- /** - The description of the subcommand. Empty string if not provided */
40
- readonly description: string;
41
-
42
- /** - The placeholder of the subcommand. Empty string if not provided */
43
- readonly placeholder: string;
44
-
45
- /** - The usage of the subcommand. Empty string if not provided */
46
- readonly usage: string;
47
-
48
- /** - The example of the subcommand. Empty string if not provided */
49
- readonly example: string;
50
-
51
- /** - Whether the subcommand allows positional arguments. */
52
- readonly allowPositional: boolean;
53
-
54
- /** - The options of the subcommand. Empty array if not provided */
55
- readonly options: OptionMetadata[];
56
-
57
- /** - The arguments of the subcommand. Empty array if not provided */
58
- readonly arguments: ArgumentMetadata[];
59
- }
60
-
61
- export interface OptionMetadata {
62
- /** The option name in camelCase. E.g. `optionName` */
63
- readonly name: string;
64
-
65
- /** The option name in kebab-case. E.g. `--option-name` */
66
- readonly nameAsArg: string;
67
-
68
- /** - The aliases of the option in camelCase. Empty array if not provided. E.g. `[aliasName, ...]` */
69
- readonly aliases: string[];
70
-
71
- /** - The aliases of the option in kebab-case. Empty array if not provided. E.g. `[--alias-name, ...]` */
72
- readonly aliasesAsArgs: string[];
73
-
74
- /** - The description of the option. Empty string if not provided */
75
- readonly description: string;
76
-
77
- /** - The placeholder of the option. Empty string if not provided */
78
- readonly placeholder: string;
79
-
80
- /** - The example of the option. Empty string if not provided */
81
- readonly example: string;
82
-
83
- /** - The default value of the option. */
84
- readonly defaultValue: unknown;
85
-
86
- /** - The default value of the option as string. */
87
- readonly defaultValueAsString: string;
88
-
89
- /** - Whether the option is optional. */
90
- readonly optional: boolean;
91
-
92
- /** - The zod type of the option. */
93
- readonly type: z.ZodTypeAny;
94
- }
95
-
96
- export interface ArgumentMetadata {
97
- /** The argument name. */
98
- readonly name: string;
99
-
100
- /** - The description of the argument. Empty string if not provided */
101
- readonly description: string;
102
-
103
- /** - The example of the argument. Empty string if not provided */
104
- readonly example: string;
105
-
106
- /** - The default value of the argument. */
107
- readonly defaultValue: unknown;
108
-
109
- /** - The default value of the argument as string. */
110
- readonly defaultValueAsString: string;
111
-
112
- /** - Whether the argument is optional. */
113
- readonly optional: boolean;
114
-
115
- /** - The zod type of the argument. */
116
- readonly type: z.ZodTypeAny;
117
- }
10
+ export type ZodInfer<T extends Schema> = T extends SchemaV4 ? Z4.infer<T> : T extends SchemaV3 ? Z3.infer<T> : never;
118
11
 
119
12
  export type Subcommand = {
120
13
  /**
121
- * - The subcommand name, use `kebab-case`.
14
+ * - The subcommand name
122
15
  * - Make sure to not duplicate commands and aliases.
123
16
  *
124
17
  * @example
@@ -182,11 +75,21 @@ export type Subcommand = {
182
75
  * const helpCommand = createSubcommand({ name: "help", options: [...] });
183
76
  * helpCommand.setAction(res => console.log(res));
184
77
  */
185
- action?: (results?: any) => void;
78
+ action?: (results?: any) => any;
79
+
80
+ /**
81
+ * - The preValidation hook is executed before the action.
82
+ * - To get typescript types use `setPreValidationHook` instead of this.
83
+ *
84
+ * @example
85
+ * const helpCommand = createSubcommand({ name: "help", options: [...] });
86
+ * helpCommand.setPreValidationHook(ctx => console.log(ctx));
87
+ */
88
+ preValidation?: (ctx?: any) => any;
186
89
  };
187
90
 
188
91
  export type Cli = Prettify<
189
- Omit<Subcommand, "name"> & {
92
+ Omit<Subcommand, "name" | "aliases" | "placeholder"> & {
190
93
  /** - The name of the CLI program. */
191
94
  cliName: string;
192
95
  }
@@ -194,22 +97,22 @@ export type Cli = Prettify<
194
97
 
195
98
  export type Option = {
196
99
  /**
197
- * - The name of the option, use `CamelCase`.
198
- * - For example: the syntax for the option `rootPath` is `--root-path`.
100
+ * The name of the option, use a valid **JavaScript** variable name.\
101
+ * **Supports:** `camelCase`, `PascalCase`, `snake_case`, and `SCREAMING_SNAKE_CASE`.\
102
+ * **Examples:**
103
+ *
104
+ * - `I` or `i` ➡️ `-i`
105
+ * - `InputDir`, `inputDir`, or `INPUT_DIR` ➡️ `--input-dir`
106
+ * - `Help`, `help`, or `HELP` ➡️ `--help`
199
107
  */
200
108
  name: string;
201
109
 
202
110
  /**
203
111
  * - The will be used to validate the user input.
204
112
  *
205
- * @example
206
- * type: z.boolean().default(false);
207
- * type: z.coerce.number(); // will be coerced to number by Zod
208
- * type: z.preprocess(parseStringToArrFn, z.array(z.coerce.number())); // array of numbers
209
- *
210
- * @see https://zod.dev/?id=types
113
+ * @see https://zod.dev/api
211
114
  */
212
- type: z.ZodTypeAny;
115
+ type: Schema;
213
116
 
214
117
  /**
215
118
  * - The description of the option.
@@ -241,14 +144,9 @@ export type Argument = {
241
144
  /**
242
145
  * - The will be used to validate the user input.
243
146
  *
244
- * @example
245
- * type: z.boolean();
246
- * type: z.coerce.number(); // will be coerced to number by Zod
247
- * type: z.preprocess(ParseStringToArrFn, z.array(z.coerce.number())); // array of numbers
248
- *
249
- * @see https://zod.dev/?id=types
147
+ * @see https://zod.dev/api
250
148
  */
251
- type: z.ZodTypeAny;
149
+ type: Schema;
252
150
 
253
151
  /**
254
152
  * - The description of the argument.
@@ -265,52 +163,21 @@ export type Argument = {
265
163
 
266
164
  export type ColorFnType = (...text: unknown[]) => string;
267
165
 
268
- export type PrintHelpOpt = {
269
- /**
270
- * - **Optional** `boolean`
271
- * - Whether to print colors or not.
272
- * - Default: `true`
273
- */
274
- colors?: boolean;
275
-
276
- /**
277
- * - **Optional** `object`
278
- * - The colors to use for the help message.
279
- */
280
- customColors?: {
281
- title?: ColorFnType;
282
- description?: ColorFnType;
283
- default?: ColorFnType;
284
- optional?: ColorFnType;
285
- exampleTitle?: ColorFnType;
286
- example?: ColorFnType;
287
- command?: ColorFnType;
288
- option?: ColorFnType;
289
- argument?: ColorFnType;
290
- placeholder?: ColorFnType;
291
- punctuation?: ColorFnType;
292
- };
293
- };
294
-
295
- export type _Info = {
296
- /**
297
- * - The raw argument as it was passed in
298
- * - For options that have a default value and are not passed in, the raw argument will be `undefined`
299
- */
300
- rawArg?: string;
301
- /**
302
- * - The raw value of the argument as it was passed in
303
- * - It will be empty string for `boolean` options. E.g. `--help` or `-h`
304
- * - For options that have a default value and are not passed in, the raw value will be `undefined`
305
- */
306
- rawValue?: string;
307
- /**
308
- * - The source value of the argument:
309
- * - `cli`: The argument was passed in by the user
310
- * - `default`: The argument was not passed in and has a default value
311
- */
312
- source: "cli" | "default";
313
- };
166
+ /** - The colors to use for the help message. */
167
+ export type HelpMsgStyle = Record<
168
+ | "title"
169
+ | "description"
170
+ | "default"
171
+ | "optional"
172
+ | "exampleTitle"
173
+ | "example"
174
+ | "command"
175
+ | "option"
176
+ | "argument"
177
+ | "placeholder"
178
+ | "punctuation",
179
+ ColorFnType
180
+ >;
314
181
 
315
182
  /**
316
183
  * - Infer the options type from a subcommand.
@@ -320,7 +187,7 @@ export type _Info = {
320
187
  * type OptionsType = InferOptionsType<typeof subcommand>;
321
188
  */
322
189
  export type InferOptionsType<T extends Partial<Subcommand>> = T["options"] extends infer U extends Option[]
323
- ? ToOptional<{ [K in U[number]["name"]]: z.infer<Extract<U[number], { name: K }>["type"]> }>
190
+ ? ToOptional<{ [K in U[number]["name"]]: ZodInfer<Extract<U[number], { name: K }>["type"]> }>
324
191
  : undefined;
325
192
 
326
193
  /**
@@ -331,7 +198,7 @@ export type InferOptionsType<T extends Partial<Subcommand>> = T["options"] exten
331
198
  * type ArgumentsType = InferArgumentsType<typeof subcommand>;
332
199
  */
333
200
  export type InferArgumentsType<T extends Partial<Subcommand>> = T["arguments"] extends infer U extends Argument[]
334
- ? { [K in keyof U]: U[K] extends { type: z.ZodTypeAny } ? z.infer<U[K]["type"]> : never }
201
+ ? { [K in keyof U]: U[K] extends { type: Schema } ? ZodInfer<U[K]["type"]> : never }
335
202
  : undefined;
336
203
 
337
204
  /** `{ some props } & { other props }` => `{ some props, other props }` */
@@ -341,68 +208,36 @@ export type Prettify<T> = { [K in keyof T]: T[K] } & {};
341
208
  export type LiteralUnion<T extends string> = T | (string & {});
342
209
 
343
210
  /** Extract the undefined properties from an object */
344
- type UndefinedProperties<T> = { [P in keyof T]-?: undefined extends T[P] ? P : never }[keyof T];
211
+ export type UndefinedProperties<T> = { [P in keyof T]-?: undefined extends T[P] ? P : never }[keyof T];
345
212
 
346
213
  /** Make undefined properties optional? */
347
- type ToOptional<T> = Prettify<
214
+ export type ToOptional<T> = Prettify<
348
215
  Partial<Pick<T, UndefinedProperties<T>>> & Pick<T, Exclude<keyof T, UndefinedProperties<T>>>
349
216
  >;
350
217
 
351
- export type OptionsArr2RecordType<T extends Option[] | undefined> = T extends Option[]
352
- ? ToOptional<{ [K in T[number]["name"]]: z.infer<Extract<T[number], { name: K }>["type"]> }>
353
- : object;
354
-
355
- export type ArgumentsArr2ArrType<T extends Argument[] | undefined> = T extends Argument[]
356
- ? { arguments: { [K in keyof T]: T[K] extends { type: z.ZodTypeAny } ? z.infer<T[K]["type"]> : never } }
357
- : object;
358
-
359
- export type Positional<S extends Partial<Subcommand>> = S["allowPositional"] extends true
360
- ? { positional: string[] }
361
- : object;
362
-
363
- export type Info<T extends Option[] | undefined> = T extends Option[]
364
- ? {
365
- _info: ToOptional<{
366
- [K in T[number]["name"]]: Extract<T[number], { name: K }> extends infer U extends Option
367
- ? undefined extends z.infer<U["type"]>
368
- ? undefined | Prettify<_Info & U> // if optional add undefined
369
- : Prettify<_Info & U>
370
- : never;
371
- }>;
372
- }
373
- : object;
374
-
375
218
  export type NoSubcommand = { name: undefined };
376
219
 
377
- export type ParseResult<S extends Partial<Subcommand>[]> = {
378
- [K in keyof S]: Prettify<
379
- { subcommand: S[K]["name"] } & Positional<S[K]> &
380
- Info<S[K]["options"]> &
381
- OptionsArr2RecordType<S[K]["options"]> &
382
- ArgumentsArr2ArrType<S[K]["arguments"]>
383
- >;
384
- }[number];
385
-
386
220
  export type PrintMethods<N extends Subcommand["name"]> = {
387
- printCliHelp: (options?: PrintHelpOpt) => void;
388
- printSubcommandHelp: (subcommand: LiteralUnion<NonNullable<N>>, options?: PrintHelpOpt) => void;
221
+ printCliHelp: (style?: Partial<HelpMsgStyle>) => void;
222
+ printSubcommandHelp: (subcommand: LiteralUnion<NonNullable<N>>, style?: Partial<HelpMsgStyle>) => void;
389
223
  };
390
224
 
391
- export type UnSafeParseResult<S extends Partial<Subcommand>[]> =
225
+ export type UnsafeParseResult<S extends Partial<Subcommand>[]> =
392
226
  CheckDuplicatedSubcommands<S> extends infer E extends string
393
227
  ? E
394
- : Prettify<ParseResult<S> & PrintMethods<NonNullable<S[number]["name"]>>>;
228
+ : Prettify<ValidateResult<S> & PrintMethods<NonNullable<S[number]["name"]>>>;
395
229
 
396
230
  export type SafeParseResult<S extends Partial<Subcommand>[]> =
397
231
  CheckDuplicatedSubcommands<S> extends infer E extends string
398
232
  ? E
399
233
  : Prettify<
400
- ({ success: false; error: Error } | { success: true; data: ParseResult<S> }) &
234
+ ({ success: false; error: Error } | { success: true; data: ValidateResult<S> }) &
401
235
  PrintMethods<NonNullable<S[number]["name"]>>
402
236
  >;
403
237
 
404
- export type ActionFn<T extends Subcommand | Cli> = {
405
- setAction: (actions: (res: UnSafeParseResult<[T]>) => void) => void;
238
+ export type ActionsFn<T extends Subcommand | Cli> = {
239
+ setAction: (actions: (res: UnsafeParseResult<[T]>) => void) => void;
240
+ setPreValidationHook: (hookFn: (ctx: ParseResult<[T]>) => void) => void;
406
241
  };
407
242
 
408
243
  /** - Combine `name` and `aliases` to a `string[]` */
@@ -430,20 +265,51 @@ type IsDuplicatesInArr<Input extends any[]> = Input extends [infer Item, ...infe
430
265
  /**
431
266
  * - Check if there are duplicated options including aliases in `subcommand`
432
267
  * - Return an error message if duplicated is found
433
- * - Return `subcommand` if not found
268
+ * - Return `undefined` if not found
434
269
  */
435
270
  export type CheckDuplicatedOptions<T extends { options?: Option[] }> = T["options"] extends infer O extends Option[]
436
- ? IsDuplicatesInArr<MapNameAndAliases2StrArr<O>> extends infer D extends string
437
- ? `>>> Error: Duplicated Options \`${D}\` <<<`
438
- : T
439
- : T;
271
+ ? IsDuplicatesInArr<MapNameAndAliases2StrArr<O>> extends infer Name extends string
272
+ ? `>>> Error: Duplicated Options. Check the options with the name \`${Name}\` <<<`
273
+ : undefined
274
+ : undefined;
440
275
 
441
276
  /**
442
277
  * - Check for duplicated subcommands including aliases
443
278
  * - Return an error message if duplicated is found
444
- * - Return the `subcommand[]` if no error
279
+ * - Return the `undefined` if no error
280
+ */
281
+ type CheckDuplicatedSubcommands<T extends Partial<Subcommand>[]> =
282
+ IsDuplicatesInArr<MapNameAndAliases2StrArr<T>> extends infer Name extends string
283
+ ? `>>> Error: Duplicated Subcommand. Check the subcommands with the name \`${Name}\` <<<`
284
+ : undefined;
285
+
286
+ /**
287
+ * - Check for duplicated arguments
288
+ * - Return an error message if duplicated is found
289
+ * - Return the `undefined` if no error
290
+ */
291
+ export type CheckDuplicatedArguments<T extends { arguments?: Argument[] }> = T["arguments"] extends infer A extends
292
+ Argument[]
293
+ ? IsDuplicatesInArr<MapNameAndAliases2StrArr<A>> extends infer Name extends string
294
+ ? `>>> Error: Duplicated Arguments. Check the arguments with the name \`${Name}\` <<<`
295
+ : undefined
296
+ : undefined;
297
+
298
+ type OptionalUnion = Z3.ZodOptional<Z3.ZodAny> | Z4.$ZodOptional | Z3.ZodDefault<Z3.ZodAny> | Z4.$ZodDefault;
299
+
300
+ /**
301
+ * - Insures that only the last argument is optional
302
+ * - Insures no optional arguments are allowed when `allowPositional` is enabled
445
303
  */
446
- export type CheckDuplicatedSubcommands<T extends Partial<Subcommand>[]> =
447
- IsDuplicatesInArr<MapNameAndAliases2StrArr<T>> extends infer D extends string
448
- ? `>>> Error: Duplicated Subcommand \`${D}\` <<<`
304
+ export type CheckArgumentsOptional<T extends { allowPositional?: boolean; arguments?: readonly Argument[] }> =
305
+ T["arguments"] extends readonly [...infer Rest, infer Last]
306
+ ? Last extends { type: OptionalUnion }
307
+ ? T["allowPositional"] extends true
308
+ ? `>>> Error: Cannot have optional arguments when \`allowPositional\` is enabled. The argument \`${Last extends { name: string } ? Last["name"] : ""}\` should not be optional <<<`
309
+ : T
310
+ : Extract<Rest[number], { type: OptionalUnion }> extends never
311
+ ? T
312
+ : T["allowPositional"] extends true
313
+ ? `>>> Error: Cannot have optional arguments when \`allowPositional\` is enabled. The argument \`${Rest[number] extends { name: string } ? Rest[number]["name"] : ""}\` should not be optional <<<`
314
+ : `>>> Error: Only the last argument may be optional. The argument \`${Rest[number] extends { name: string } ? Rest[number]["name"] : ""}\` should not be optional <<<`
449
315
  : T;