Comments (16)
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 ./my-program -vvvv -v
output '-v': 5
?
What if the flag '-vvv'
exists? Should the following return case 1 or case 2?
// ./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 😅
from arg.
@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 args.x.filter(x => x).length
(though obviously more verbose).
In any case, shouldn't type()
always be called? I was just reading the code and I'd expect something like -x false
to work (in case the default is true
in code).
from arg.
Agreed that returning a number for [Boolean]
flags seems strange. Seems like the natural solution is to return an array of booleans [true, true, true, ...]
and let the user call .length
on it themselves.
The core of the issue still exists though: repeating single-hyphen flags should push additional true values onto that array.
from arg.
Using your example above, should
./my-program -vvvv -v
output'-v': 5
?
Yes. :)
What if the flag
'-vvv'
exists?
It won't; it's one of arg
's few opinions. Single-dash options are only single letters - we have #4 open to enforce this as the example snippet you provided should throw an error.
from arg.
@blakeembrey Boolean
is already a special case in arg
. -x false
and -x true
are not common GNU argument parsing patterns for booleans. In those cases, false
and true
would become positional arguments (assuming -x
is a boolean type).
That also means that if we kept the current functionality, you'll always end up with an array of true
's, which doesn't really add much information aside from using .length
anyway.
Further, it makes parsing for condensed arguments (-abcd
instead of -a -b -c -d
) a bit less intuitive if you accept boolean strings.
The only two edge cases are then:
Boolean
- if the flag is present, thentrue
; otherwise,false
[Boolean]
- always aNumber
, always present and0 < n
, that counts the number of occurrences of the flag in the command line.
Otherwise, all types are as you would expect.
from arg.
@Qix- I see. Thoughts on using an internal boolean
symbol instead (e.g. export const POSITIONAL = Symbol('positional')
(or even '__POSITIONAL__'
for older systems)? I'm just thinking about how this from documentation in the README and TypeScript. In terms of TypeScript, it'd require an overload in either case to override Boolean
behaviour when the numeric is introduced so feel free to ping me then.
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 true
or false
if it can never be false
anyway.
from arg.
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 [Boolean]
argument types are always numbers.
from arg.
@Qix- Just API consistency. Right now things are super easy to understand, and there's no documentation on Boolean
really needed (even though it is special). After this, in either case, you need to write documentation on the new special behavior. I just thought it was more consistent to introduce a new behavior instead of a change to special case to existing statements. E.g. this statement is false now:
This means the built-in String, Number, and Boolean type constructors "just work" as type functions.
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 [Boolean]
actually produces a number. But, you know, everything else is true to the statement above.
from arg.
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 [Boolean]
from arg.
The problem right now is that to specify multiple levels of verbosity, for example, you have to add -v -v -v -v
(-vvvv
does not work). That's not very GNU-like at all.
Can we at least adopt the ability to do -vvvv
even though we keep [true, true, true, true]
?
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 [Boolean]
has special handling.
Getting back [true, true, true, true, true]
where the true
will never be anything other than true
is what's less elegant in my opinion. The only meaningful information you'd get from [Boolean]
arguments is by using .length
.
from arg.
@Qix- I do agree by the way! How do you feel about the constant instead of overloading the built-in Boolean
function? Is there a name for this behavior? It could just be:
arg({
'-x': arg.BOOL // `arg.COUNT`, `arg.POS`, `arg.SEEN`, `arg.EXISTS`, `arg.<name of behavior>`
})
I just noticed the third argument too:
The previous value for the destination (useful for reduce-like operatons or for supporting -v multiple times, etc.)
This could be supported by providing arg.COUNT
which takes over Boolean
and does (_, _, i = 0) => i + 1
.
from arg.
@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?
from arg.
@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)
})
from arg.
@blakeembrey Right, but that means losing the simplicity of [Type]
.
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'
});
from arg.
If we want to keep the simplicity of [Type]
but avoid the redundancy of returning an array that will only ever contain true
values, how about faking it by using [Boolean].length
?
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 1
instead of [Boolean].length
) but it would work. Thoughts?
// ./my-program -vv -xxx
const args = arg({
'-v': [Boolean].length,
'-x': [Boolean]
});
/*
{
'-v': 2,
'-x': [true, true, true]
}
*/
from arg.
That feels like a hack :/ I'd say -1 on it.
I still think the symbol and helper method is the way to go.
from arg.
Related Issues (20)
- Separate `--` and `_` arguments HOT 13
- Ability to "stop early" HOT 9
- Add code coverage analysis + badge
- Print help? HOT 2
- Support defaults HOT 8
- `arg` parses quoted argument values HOT 2
- Support for required arguments? HOT 2
- Everything after "=" gets stripped off in long args with "=" in value HOT 1
- Short args can't be used with = HOT 7
- Issues parsing negative numbers when passed without `=` HOT 13
- What's the default value for Boolean type? HOT 3
- Is there other way to input array of strings? HOT 3
- Add support for running in the browser HOT 2
- Typescript build error HOT 1
- Flags with optional values HOT 2
- TypeScript typings error for handlers
- Add support for Deno HOT 4
- Convert to ES Modules
- Short options get splited in permissive being true
- ReDoS vulnerability in index.js
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from arg.