Skip to content

Commit 60221f5

Browse files
committed
Fix short-flag number values
1 parent a2af21e commit 60221f5

File tree

3 files changed

+40
-37
lines changed

3 files changed

+40
-37
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const cli = createCLI({
2828
version: '1.0.0',
2929
description: 'My CLI tool',
3030
commands: [
31-
{
31+
createCommand({
3232
name: 'greet',
3333
description: 'Greet someone',
3434
args: z.object({
@@ -39,7 +39,7 @@ const cli = createCLI({
3939
const greeting = `Hello, ${name}!`;
4040
console.log(uppercase ? greeting.toUpperCase() : greeting);
4141
}
42-
}
42+
})
4343
]
4444
});
4545

lib/parse.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ describe('parseArgs', () => {
3030
expect(result).toEqual({ number: 123 })
3131
})
3232

33+
it('should parse short-form number flags', () => {
34+
const schema = z.object({
35+
number: z.number()
36+
})
37+
const argv = ['-n', '123']
38+
const result = parseArgs({ argv, schema })
39+
expect(result).toEqual({ number: 123 })
40+
})
41+
3342
it('should convert kebab-case flags to camelCase', () => {
3443
const schema = z.object({
3544
kebabCase: z.boolean().optional()

lib/parse.ts

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -76,55 +76,49 @@ export function parseArgs<T extends z.ZodType>({
7676
const flagMatch = arg.match(FLAG_REGEX)
7777
const shortMatch = arg.match(SHORT_FLAG_REGEX)
7878

79+
let flagName = ''
80+
7981
if (shortMatch) {
8082
const flags = (shortMatch[1] || '').split('')
8183
for (const flag of flags) {
8284
if (schema instanceof z.ZodObject) {
83-
const shape = schema.shape
85+
const { shape } = schema
8486
const keys = Object.keys(shape)
8587
const matchingKey = keys.find(k => k.toLowerCase().startsWith(flag.toLowerCase()))
86-
if (matchingKey) {
87-
args[matchingKey] = nextIsValue ? nextArg : true
88-
if (nextIsValue) i++ // Skip the next arg
89-
}
88+
flagName = matchingKey || ''
9089
}
9190
}
9291
}
9392

94-
if (flagMatch) {
95-
const flagName = kebabToCamel(flagMatch[1] || '')
96-
97-
// TODO: map between Zod types in a flat, extensible way
98-
let isBoolean = false
99-
let isNumber = false
100-
if (schema instanceof z.ZodObject) {
101-
const shape = schema.shape
102-
const field = shape[flagName]
103-
if (field) {
104-
if (field instanceof z.ZodBoolean) {
105-
isBoolean = true
106-
} else if (field instanceof z.ZodOptional && field.unwrap() instanceof z.ZodBoolean) {
107-
isBoolean = true
108-
} else if (field instanceof z.ZodNumber) {
109-
isNumber = true
110-
} else if (field instanceof z.ZodOptional && field.unwrap() instanceof z.ZodNumber) {
111-
isNumber = true
112-
}
93+
if (flagMatch) flagName = kebabToCamel(flagMatch[1] || '')
94+
95+
// TODO: map between Zod types in a flat, extensible way
96+
if (schema instanceof z.ZodObject) {
97+
const { shape } = schema
98+
let field = shape[flagName]
99+
if (field) {
100+
if (field instanceof z.ZodOptional) field = field.unwrap()
101+
if (field instanceof z.ZodDefault) field = field.unwrap()
102+
103+
if (field instanceof z.ZodBoolean) {
104+
args[flagName] = true
105+
continue
113106
}
114-
}
115107

116-
if (isNumber) {
117-
args[flagName] = Number(nextArg)
118-
i++ // Skip the next arg
119-
} else if (isBoolean) {
120-
args[flagName] = true
121-
} else if (nextIsValue) {
122-
args[flagName] = nextArg
123-
i++ // Skip the next arg
124-
} else {
125-
throw new Error(`Missing value for flag --${flagMatch[1]}`)
108+
if (field instanceof z.ZodNumber) {
109+
args[flagName] = Number(nextArg)
110+
i++ // Skip the next arg
111+
continue
112+
}
126113
}
127114
}
115+
116+
if (nextIsValue) {
117+
args[flagName] = nextArg
118+
i++ // Skip the next arg
119+
} else {
120+
throw new Error(`Missing value for flag --${flagName}`)
121+
}
128122
}
129123

130124
const { data, success, error } = schema.safeParse(args)

0 commit comments

Comments
 (0)