Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option alias doesn't work in combination with zod.default()/zod.optional() #65

Open
ulken opened this issue Nov 27, 2023 · 3 comments
Open

Comments

@ulken
Copy link

ulken commented Nov 27, 2023

I'm trying to define an alias for an option, but it's not working if used with neither zod.default() nor zod.optional().

Try it out: https://codesandbox.io/p/devbox/infallible-jones-ys358t?file=/string-default-alias/source/commands/index.tsx:6,1

Run npm run build (maybe followed by npm link) and then da -h.

Works 👍

export const options = zod.object({
	name: zod
		.string()
		.describe(option({alias: 'n', description: 'Name'})),
});

Outputs:

❭  sda -h       
Usage: sda [options]

Options:
  -n, --name <name>  Name
  -v, --version      Show version number
  -h, --help         Show help

Doesn't work 👎

export const options = zod.object({
	name: zod
		.string()
		.default('Stranger')
		.describe(option({alias: 'n', description: 'Name'})),
});

and

export const options = zod.object({
	name: zod
		.string()
		.optional()
		.describe(option({alias: 'n', description: 'Name'})),
});

Outputs:

❭  sda -h       
Usage: sda [options]

Options:
  --name [name]  Name (default: 1)
  -v, --version  Show version number
  -h, --help     Show help

(default only in the first case, obviously)

@ulken
Copy link
Author

ulken commented Nov 27, 2023

Same thing happens with zod.number(), so not isolated to zod.string().

@ulken
Copy link
Author

ulken commented Nov 27, 2023

@vadimdemedes I started looking into it. Even though I lack knowledge of Zod's internals, judging by generate-options.ts#L66C3-L89C52:

Code

const description = getDescription(optionSchema.description);
let valueDescription = getValueDescription(optionSchema.description);
let isOptional = isOptionalByDefault;

// Unwrap zod.string().optional()
if (optionSchema instanceof ZodOptional) {
    isOptional = true;
    optionSchema = optionSchema._def.innerType;
}

// Unwrap zod.string().optional().default()
if (optionSchema instanceof ZodDefault) {
    isOptional = true;
    defaultValue = optionSchema._def.defaultValue();
    optionSchema = optionSchema._def.innerType;
}

// Unwrap zod.string().default().optional()
if (optionSchema instanceof ZodOptional) {
    isOptional = true;
    optionSchema = optionSchema._def.innerType;
}

const alias = getAlias(optionSchema.description);
let flag = `--${name}`;

my best guess is by reassigning optionSchema to _def.innerType, we lose the special __parsel prefix of description, causing the config lookup to "fail".

getAlias() is the only config lookup from there on, so I suppose it supports that theory?

Potential fixes:

  1. Move getAlias() before the reassignment
  2. Store the original "raw" description value and pass that to getAlias()

I might be missing something, though.

@ulken
Copy link
Author

ulken commented Dec 5, 2023

@vadimdemedes I'll gladly help out here if you could just give your thoughts on the matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant