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

Refactor parsing for readability and future expansion, and tighten short option group parsing #68

Closed
wants to merge 13 commits into from

Conversation

shadowspawn
Copy link
Collaborator

@shadowspawn shadowspawn commented Feb 26, 2022

  1. Refactor parsing:
  • improve readability
  • reduce logic nesting and simplify context for readability
  • make it easier to add further functionality

Refactor heavily influenced by comments and code from @aaronccasanova in #64.

  1. There is one functional change. A dubious option group with an option in the middle taking a value now returns the argument as a positional for BYO handling, and in strict mode this would throw. (The previous code was blindly expanding anything after a single -.) This behaviour influenced by comments from @ljharb, and narrower implementation of the Open Group Utility Conventions.

  2. Separate out and extend tests for single - and for short option groups.

Apologies for the noise moving the tests, but something I badly wanted to do, and felt in scope for a big refactor!


First draft: no changes to unit tests. It works as before, as far as the tests went!
Second draft: separate out and extend - unit tests
Third draft: separate out and extend short option group tests

@aaronccasanova
Copy link
Collaborator

These updates are great @shadowspawn!! I'm honestly tempted to close out my PR in favor of this implementation. My goal was simply to swap out the conditionals with named utilities while introducing the smallest number of changes. That being said, I very much prefer the approach you took where each arg is assessed sequentially and the utility functions can stand on their own 👌

@shadowspawn shadowspawn marked this pull request as ready for review February 26, 2022 04:03
@shadowspawn
Copy link
Collaborator Author

Ready for review.

index.js Outdated Show resolved Hide resolved
index.js Outdated Show resolved Hide resolved
index.js Outdated Show resolved Hide resolved
index.js Outdated Show resolved Hide resolved
* Determines if the option is expecting a value.
*/
function isExpectingValue(optionKey, options) {
return options && options.withValue &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return options && options.withValue &&
return options && ArrayIsArray(options.withValue) &&

otherwise a truthy non-array could cause problems

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We call validateArray on withValue as soon as the options are received, so don't need to be paranoid about that. (Good advice in just local scope. The validation is outside the diff.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we're sure it's an array when present, why would options be falsy?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be missing with current validation:

if (ObjectHasOwn(options, key)) {

(We currently validate, but not modify. Might be revamping configuration: #63)

test/dash.js Show resolved Hide resolved
test/dash.js Show resolved Hide resolved
Comment on lines +209 to +215
* @example
* isLongOption('-a) // returns false
* isLongOption('--foo) // returns true
* isLongOption('--foo=bar) // returns true
*/
function isLongOption(arg) {
return arg.length > 2 && StringPrototypeStartsWith(arg, '--');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLongOption('---') would also return true. Should we update this to test with regex?
e.g. /^--?\w+/.test(arg)

Or simply add && StringPrototypeCharAt(arg, 2) !== '-'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLongOption('---') would also return true.

Yes, this is an edge case but is as intended. See discussion in #7.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roger roger, thanks for the resource! Skimming the issue I'm in agreement it makes sense we limit the assumption here 👍

index.js Outdated
Comment on lines 197 to 199
const onlyFlags = arg.slice(1, -1);
for (let index = 0; index < onlyFlags.length; index++) {
const optionKey = getOptionKey(StringPrototypeCharAt(onlyFlags, index));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): This appears to be the only place in the parsing implementation referring to options as flags (outside of the results object). Perhaps we should update the name for consistency e.g. optionKeys, onlyOptionKeys, shortOptions, onlyShortOptions, etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha! I knew that when I wrote it, but didn't try and think of something better! Fair call, will do. 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked wording and code:

const leadingShorts = StringPrototypeSlice(arg, 1, -1);
const allLeadingAreBoolean = ArrayPrototypeEvery(leadingShorts, (short) => {

index.js Outdated Show resolved Hide resolved
shadowspawn and others added 2 commits February 26, 2022 19:14
Co-authored-by: Jordan Harband <ljharb@gmail.com>
@@ -53,7 +54,7 @@ function getMainArgs() {
return ArrayPrototypeSlice(process.argv, 2);
}

function storeOptionValue(parseOptions, option, value, result) {
function storeOptionValue(option, value, parseOptions, result) {
const multiple = parseOptions.multiples &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like if we’re validating such that we know this is an array, why isn’t it always an array? Meaning, have it be an empty array here, rather than falsy/missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(We currently validate, but not modify. Might be revamping configuration: #63)

This was referenced Feb 26, 2022
@bcoe
Copy link
Collaborator

bcoe commented Feb 27, 2022

@aaronccasanova, if you prefer this over #64, let's go with it?

Same comment stands as in #64, which is that I'd advocate that we keep these helpers private.

@aaronccasanova
Copy link
Collaborator

Yes, I prefer this implementation and agree the helpers should be private 👍 Wen't ahead and closed PR #64

@shadowspawn
Copy link
Collaborator Author

I am working on rewrite for after #63 lands, so changed this to draft.

@shadowspawn
Copy link
Collaborator Author

Working on redo of this with new configuration bag of options.

@shadowspawn
Copy link
Collaborator Author

Redid work in #75 after #63 landed.

@shadowspawn shadowspawn closed this Mar 4, 2022
@shadowspawn shadowspawn deleted the feature/more-shorts branch June 5, 2022 03:17
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

Successfully merging this pull request may close these issues.

4 participants