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

coerce works... and then unworks #2430

Open
digitalsadhu opened this issue Aug 28, 2024 · 7 comments
Open

coerce works... and then unworks #2430

digitalsadhu opened this issue Aug 28, 2024 · 7 comments

Comments

@digitalsadhu
Copy link

I have some code that looks like this:

yargs(hideBin(process.argv))
	.options({
		config: {
			alias: "c",
			describe:
				"Provide an exact path to an eik.json or package.json file to use as config. Default is eik.json in the current working directory.",
			coerce: (val) => {
				if (isAbsolute(val)) {
					return val;
				}
				return join(process.cwd(), val);
			},
		},
...

and I use it with something like:

my-command --config ../eik-static.json

And when I log yarns.argv 2x like this:

console.log(yargs.argv.config, yargs.argv.config);

The first is correct and the second has reverted to the value before coercion.

/Users/[email protected]/src/frontpage-podium/eik-static.json
./eik-static.json

Any idea what I'm doing wrong?

@yargs yargs deleted a comment Aug 28, 2024
@shadowspawn
Copy link
Member

A quick answer. Despite appearances yargs.argv is actually a getter function call, and is deprecated due to the potential for confusion. The recommended replacement is to call yargs.parse() (or parseAsync() or parseSync()) which make it much clearer what is going on.

In particular, you want to store the results of the parse and not parse twice. Then you should "obviously" get the same results twice! e.g.

const argv = yargs.argv;
console.log(argv.config, argv.config);

@digitalsadhu
Copy link
Author

digitalsadhu commented Aug 28, 2024

Ah thanks for the quick reply.

The trouble is, I'm exporting a builder function and a handler function and argv is not the same in each.

export const builder = (yargs) => {
	const argv = yargs.argv; // correct here
};

export const handler = async (argv) => {
	console.log(argv); // wrong here
}

I can hack it like this:

let argv;

export const builder = (yargs) => {
	argv = yargs.argv; // correct here
};

export const handler = async () => {
	console.log(argv); // correct here
}

but this kinda defeats the purpose of the coercing upstream

@yargs yargs deleted a comment Aug 28, 2024
@shadowspawn
Copy link
Member

Basically, it does not make sense to call parse (or .argv) from inside the builder function. Try removing that call.

The relevant part of the documentation is:

Note: .parse() should only be used at the top level, not inside a command’s builder function.

https://yargs.js.org/docs/#api-reference-commandcmd-desc-builder-handler

@digitalsadhu
Copy link
Author

digitalsadhu commented Aug 28, 2024

I can't really as we dynamically set defaults in the builder function based on a config file we lookup based on user input.

eg.

export const builder = (yargs) => {
	const argv = yargs.argv;
	const defaults = getDefaults(argv.config);

	yargs
		.positional("name", {
			describe: "Name matching a package or import map on the Eik server",
			type: "string",
			default: defaults.name,
		})
        ....

If you have any suggestions about how a more yargs idiomatic way of doing this is that would be great but otherwise It's ok, I can just not use the coerce function.

And thanks for your help :)

@shadowspawn
Copy link
Member

I wondered whether your simpler examples were leading to a more complex scenario. 😄

What you are currently doing is parsing the inputs in the builder (by calling yargs.argv), then changing the yargs configuration, then parsing the inputs again later using the same yargs object. That is not a supported workflow.

A couple of ideas:

  • yargs has support for a configuration file, if it matches your needs, or
  • to find the config file from the command-line args, parse using a fresh yargs instance which only cares about the --config option and is not strict

I have experimented with the double-pass approach with a different parsing library, but not tried it with yargs myself. If that doesn't make sense I can try and knock up an example but that will be some days away.

@yargs yargs deleted a comment Aug 28, 2024
@digitalsadhu
Copy link
Author

Ill look into the configuration file thing you mention, thanks so much for your help!

@jkrems
Copy link

jkrems commented Sep 9, 2024

Would it make sense to actively throw when parse is called a 2nd time? It seems like its current behavior is "silently returns random values" (relative to its arguments). Or add a deprecation warning for repeated calls?

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

3 participants