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
Handle boolean array arguments better #11
Comments
I have completed this, but I could use a few more use-cases to ensure it serves the correct purpose. Using your example above, should What if the flag // ./my-program -vvv -vvv
const args = arg({
'-vvv': Boolean,
'-v': [Boolean]
});
console.log(args);
/*
{
_: [],
// case 1...
'-vvv': true,
'-v': 3
// or case 2...
'-vvv': true
}
*/ Don't want to miss an edge case 😅 |
Yes. :)
It won't; it's one of |
@Qix- Is there a common use-case where making a special case for this is worth it? It'd make it a bit confusing for anyone briefly reading the docs and it's not that hard to do In any case, shouldn't |
@blakeembrey That also means that if we kept the current functionality, you'll always end up with an array of Further, it makes parsing for condensed arguments ( The only two edge cases are then:
Otherwise, all types are as you would expect. |
@Qix- I see. Thoughts on using an internal If you use an internal symbol, would it make sense to just always be a number? I don't think I'd really care about |
I'm not sure what problem the boolean symbol would solve. Could you explain a bit more? As well, perhaps I'm missing something, but |
@Qix- Just API consistency. Right now things are super easy to understand, and there's no documentation on
Whereas just adding a new sentence mentioning positional flags is easy: arg({
'-x': arg.POS,
'-y': [arg.POS]
}) To be honest, I'm don't feel too strongly either way. I just get a little worried when I see implicit over explicit behavior of inputs since it requires people to "know" this is special and changes behavior. Imagine coming onto a new project and always explaining that |
I agree with @blakeembrey – I'd argue it's elegant to maintain type affinity. The number result is very surprising when the "type definition" is |
The problem right now is that to specify multiple levels of verbosity, for example, you have to add Can we at least adopt the ability to do FWIW, specially handling booleans is pretty universally constant. That is to say, just about every argument parser in existence that handles non-argument boolean flags has to support them specially. I don't think it's too much to understand that Getting back |
Agreed that returning a number for The core of the issue still exists though: repeating single-hyphen flags should push additional true values onto that array. |
@Qix- I do agree by the way! How do you feel about the constant instead of overloading the built-in arg({
'-x': arg.BOOL // `arg.COUNT`, `arg.POS`, `arg.SEEN`, `arg.EXISTS`, `arg.<name of behavior>`
}) I just noticed the third argument too:
This could be supported by providing |
@blakeembrey I don't hate that, though I feel strongly they should be additional rather than first-class (i.e. the parser shouldn't be aware they even exist). I think I see your point about symbols now: // issue #11 is now simply these two lines, and the branch to skip
// looking for an argument is dependent upon the type being a function (!!!)
// with the FLAG_SYM symbol.
//
// I make special note of function checks because the following would be
// invalid, but not checking for it would make the behavior inconsistent and erroneous:
//
// arg({'--verbose': Boolean, '-v': arg.FLAG_TYPE('--verbose')});
//
// In fact, an assertion/throw can happen in the case of:
//
// (typeof argType !== 'function' && argType[FLAG_SYM])
//
// EDIT: Alternatively, enforce the type checking in `arg.FLAG_TYPE()` since
// that check would happen less often and is probably better anyway.
const FLAG_SYM = Symbol('arg flag argument type');
arg.FLAG_TYPE = fn => { fn[FLAG_SYM] = true; };
// a new PR is opened to add standard helpers that build off of
// the existing argument type handler specification:
arg.COUNT = arg.FLAG_TYPE((_, _, v) => (v || 0) + 1);
arg.ENUM = map => v => {
if (v in map) return map[v];
throw new Error(`invalid argument value: ${v}`);
};
// etc... I think having some standard helpers would be nice to have. I'm not sure how far outside of the 'unix philosophy' this takes the package, though. @rauchg thoughts? |
@Qix- That's a good point. In that case, array support is just which might make that case easier: function of (fn) {
return (value, argName, prev = []) {
prev.push(fn(value))
return prev
}
}
arg({
'-x': of(String)
}) |
@blakeembrey Right, but that means losing the simplicity of Existing code would have to migrate to something like: const arg = require('arg');
const args = arg({
'--include': arg.ARRAY(String),
'-I': '--include'
}); For comparison, the existing spec which is simpler to write looks like: const args = arg({
'--include': [String],
'-I': '--include'
}); |
If we want to keep the simplicity of This correctly specifies that a number will be returned, and looking at the code correctly implicates that it will return the length of the boolean array. It feels like a hack (and you could just type // ./my-program -vv -xxx
const args = arg({
'-v': [Boolean].length,
'-x': [Boolean]
});
/*
{
'-v': 2,
'-x': [true, true, true]
}
*/ |
That feels like a hack :/ I'd say -1 on it. I still think the symbol and helper method is the way to go. |
* add shortarg condensation and arg.COUNT (closes #11) * update readme with condensed shortarg/arg.COUNT examples * add example specifically for arg.COUNT * add documentation for arg.flag()
* add shortarg condensation and arg.COUNT (closes vercel#11) * update readme with condensed shortarg/arg.COUNT examples * add example specifically for arg.COUNT * add documentation for arg.flag()
This is justified since
Boolean
types already get a bit of special treatment.In the case I want multiple levels of verbosity, for example, the following should work:
Currently, you have to do
-v -v -v -v
separately, and in turn you get[true, true, true, true]
, which isn't exactly elegant.The text was updated successfully, but these errors were encountered: