-
Notifications
You must be signed in to change notification settings - Fork 991
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
fix: coerce middleware should be applied once #1978
fix: coerce middleware should be applied once #1978
Conversation
@jly36963 thanks for digging into this one, this would be a great bug to fix. middleware was just overhauled drastically. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking reasonable to me, except I think we could extend the test to more explicitly call out the failure that's happening.
test/command.cjs
Outdated
yargs => | ||
yargs.positional('abc', { | ||
type: 'string', | ||
coerce: arg => arg.join(' '), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be worth extending this function so that it throws if coerce
is called more than once.
let executionCount = 0
...
coerce: arg => {
if (executionCount > 0) throw Error('coerce applied multiple times');
executionCount++;
return arg.join(' ');
};
I would then confirm that the test fails prior to your fix.
I made some changes to the unit test, and this is the result:
I intentionally did not put the assertions /
|
There should be no need for the `done()` since your test is assuming sync execution.
@andymcintosh @CupOfTea696 I've published @jly36963's fix to
And let us know if it fixes the issues you were bumping into? |
@bcoe yup, that fixes the issue! |
Addresses: #1966 and #1802
Debugging
I know that the coerce middleware is being applied twice.
I ran the below example. I logged the execution of the functions that use
applyMiddleware
, and I logged the type/value of the arg during coercion.Logs look like this:
The coerce middleware is only supposed to run before validation, but the pre-validation
applyMiddleware
gets called twice.Fix
stack trace
The problem
runCommand
gets called recursively, which means that the middleware gets applied for each nested command.Coerce middleware mutates argv, and repeating that mutation is undesired and can easily break.
ie:
coerce: (arg) => arg.join()
The solution
I added two properties to the Middleware interface:
mutates
defaults to false, but is set to true inaddCoerceMiddleware
.I then check each middleware during
applyMiddleware
:applied
to true.Feedback
If you have recommendations for a better pattern, or better names for the interface properties I added, let me know. I feel like they could definitely be named better.