From 7ee947bf3d1f5bd1852300d77783a4f48627dbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Est=C3=A9ban?= Date: Mon, 18 Mar 2024 15:42:45 +0100 Subject: [PATCH] feat: support `number` arg type (#73) --- playground/hello.ts | 23 +++++++++++++++++++---- src/args.ts | 17 +++++++++++++++-- src/types.ts | 25 +++++++++++++++++++++---- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/playground/hello.ts b/playground/hello.ts index 0de6f89..f49be7f 100644 --- a/playground/hello.ts +++ b/playground/hello.ts @@ -17,16 +17,31 @@ const command = defineCommand({ type: "boolean", description: "Use friendly greeting", }, - adjective: { + age: { + type: "number", + description: "Your age", + required: false, + }, + adj: { type: "enum", description: "Adjective to use in greeting", options: ["awesome", "cool", "nice"], default: "awesome", - require: false, - } + required: false, + }, }, run({ args }) { - consola.log(`${args.friendly ? "Hi" : "Greetings"} ${args.adjective} ${args.name}!`); + consola.log(args); + const msg = [ + args.friendly ? "Hi" : "Greetings", + args.adj || "", + args.name, + args.age ? `You are ${args.age} years old.` : "", + ] + .filter(Boolean) + .join(" "); + + consola.log(msg); }, }); diff --git a/src/args.ts b/src/args.ts index d067619..3d86757 100644 --- a/src/args.ts +++ b/src/args.ts @@ -10,10 +10,11 @@ export function parseArgs( const parseOptions = { boolean: [] as string[], string: [] as string[], + number: [] as string[], enum: [] as (number | string)[], mixed: [] as string[], alias: {} as Record, - default: {} as Record, + default: {} as Record, }; const args = resolveArgs(argsDef); @@ -23,7 +24,7 @@ export function parseArgs( continue; } // eslint-disable-next-line unicorn/prefer-switch - if (arg.type === "string") { + if (arg.type === "string" || arg.type === "number") { parseOptions.string.push(arg.name); } else if (arg.type === "boolean") { parseOptions.boolean.push(arg.name); @@ -49,6 +50,7 @@ export function parseArgs( }); for (const [, arg] of args.entries()) { + // eslint-disable-next-line unicorn/prefer-switch if (arg.type === "positional") { const nextPositionalArgument = positionalArguments.shift(); if (nextPositionalArgument !== undefined) { @@ -74,6 +76,17 @@ export function parseArgs( "EARG", ); } + } else if (arg.type === "number") { + const _originalValue = parsedArgsProxy[arg.name]; + parsedArgsProxy[arg.name] = Number.parseFloat( + parsedArgsProxy[arg.name] as string, + ); + if (Number.isNaN(parsedArgsProxy[arg.name])) { + throw new CLIError( + `Invalid value for argument: \`--${arg.name}\` (\`${_originalValue}\`). Expected a number.`, + "EARG", + ); + } } else if (arg.required && parsedArgsProxy[arg.name] === undefined) { throw new CLIError(`Missing required argument: --${arg.name}`, "EARG"); } diff --git a/src/types.ts b/src/types.ts index cf2cc2e..6e9387b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,14 @@ // ----- Args ----- -export type ArgType = "boolean" | "string" | "positional" | "enum" | undefined; +export type ArgType = + | "boolean" + | "string" + | "number" + | "enum" + | "positional" + | undefined; -export type _ArgDef = { +export type _ArgDef = { type?: T; description?: string; valueHint?: string; @@ -14,17 +20,22 @@ export type _ArgDef = { export type BooleanArgDef = Omit<_ArgDef<"boolean", boolean>, "options">; export type StringArgDef = Omit<_ArgDef<"string", string>, "options">; +export type NumberArgDef = Omit<_ArgDef<"number", boolean>, "options">; +export type EnumArgDef = _ArgDef<"enum", string>; export type PositionalArgDef = Omit< _ArgDef<"positional", string>, "alias" | "options" >; -export type EnumArgDef = _ArgDef<"enum", string>; + export type ArgDef = | BooleanArgDef | StringArgDef + | NumberArgDef | PositionalArgDef | EnumArgDef; + export type ArgsDef = Record; + export type Arg = ArgDef & { name: string; alias: string[] }; export type ParsedArgs = { _: string[] } & Record< @@ -37,6 +48,12 @@ export type ParsedArgs = { _: string[] } & Record< }[keyof T], string > & + Record< + { + [K in keyof T]: T[K] extends { type: "number" } ? K : never; + }[keyof T], + number + > & Record< { [K in keyof T]: T[K] extends { type: "boolean" } ? K : never; @@ -51,7 +68,7 @@ export type ParsedArgs = { _: string[] } & Record< [K in keyof T]: T[K] extends { options: infer U } ? U : never; }[keyof T] > & - Record; + Record; // ----- Command -----