jackspeak
A very strict and proper argument parser.
USAGE
Pass one or more objects into the exported jack(...)
function. Each
object can have the following fields, and would typically represent a
"section" in a usage/help output.
Using multiple sections allows for using some of the "special" fields
as argument names as well; just put them in different sections.
-
main
Function
May only appear once. If provided, will be called with the resulting
parsed object.
-
usage
String or Array
The Usage: ...
bits that go at the top of the help output
-
description
String
A heading for the section. Something like File Options
to
preface all of the options for working with files.
-
help
String
A longer-form (multi-paragraph) section of text that explains the
stuff in more details.
-
argv
Array
A list of arguments to parse. If not provided, jackspeak will
pull form process.argv
. It knows how to skip over the node binary
and main script filename.
If a section is just an array, then it'll be treated as the argv.
-
env
Object
A set of key-value pairs to pull environment variables from. If
not specified, jackspeak will pull from process.env
.
Note that environs are parsed and loaded right away when they are
defined, so you must put env
on a jackspeak object before
definint any environent
-
One or more argument definition objects. These can be formed using
the functions exported by require('jackspeak')
. The key is the
full canonical name of the argument as it appears in the parsed
result set.
Note that the --help
flag with the -h
shorthand will be added
by default, and that --
will always stop parsing and treat the
rest of the argv as positional arguments. However, help
and
--
may be added to a jack section to customize the usage text.
All types can have the following options:
-
description
- Help text for this option.
-
hidden
- Do not show this value in the help output.
-
implies
- JavaScript object of values to set in the result
objet when this flag or option is encountered in the arguments.
This can be used to have one flag enable another by default, for
example.
The types are:
-
flag(options)
- A boolean value which can be set or unset, but
not given a value.
Flags can have the following options:
-
default
- Either true
or false
. If unspecified, flags
default to false
.
-
short
- A "short" form of the value which is indicated
with a single dash. If short
is a single character, then
it can be combined gnu-style with other short flags.
-
negate
- An object defining how the --no-<whatever>
form
of the flag works. It can have any options that would be
passed to a flag, other than negate
.
For example, it can specify the help text for the negated
form, or provide a different shorthand character. So, for
example, --color
could have -c
as a shorthand, and
--no-color
could be shorthanded to -C
.
-
alias
- Either a string or array of what this flag expands
to. This means that the flag key won't have a value, but
will instead be expanded to its alias. To expand an alias
to multiple arguments, use an array. For example, in the
rsync
program, -m
expands to -r -N -l inf --no-remove-listing
-
opt(options)
- An argument which takes a value.
Opts can have the following options:
-
default
- A default value. If unspecified, opts default
to undefined
.
-
valid
- An array of valid values. If the user provides a
value outside this set, it will throw an error.
-
alias
- A string or array of options that this option
expands to when used. This works the same as flag aliases,
with the exception that you may include the string
${value}
in the alias string(s) to substitute in the value
provided to this opt.
For example, --big=<n>
could be an alias for
--font-size=<n> --bold
by doing:
jack({
big: opt({
alias: ['--font-size=${value}', '--bold']
})
})
-
hint
- A string to use in the help output as the value
provided to the opt. For example, if you wanted to print
--output=<file>
, then you'd set hint: 'file'
here.
Defaults to the opt name.
-
short
- A "short" form of the opt which is indicated
with a single dash. If short
is a single character, then
it can be combined gnu-style with short flags, and take a
value without an =
character.
For example, in tap, -bRspec
is equivalent to --bail --reporter=spec
.
-
num(options)
- An opt
that is a number. This will be
provided in the result as an actual number (rather than a
string) and will raise an error if given a non-numeric value.
This is numericized by using the +
operator, so any
JavaScript number represenation will do.
All of the opt()
options are supported, plus these:
min
- A number that this value cannot be smaller than.max
- A number that this value cannot be larger than.
-
list(options)
- An option which can take multiple values by
being specified multiple times, and is represented in the result
object as an array of values. If the list is not present in the
arguments, then it will be an empty array.
-
count(options)
- A flag which can be set multiple times to
increase a value. Unsetting decrements the value, setting
increments it. This can be useful for things like -v
to set a
verbosity level, or -d
to set a debug level.
Counts always default to 0.
Note that a count
is actually a flag that can be set
multiple times. Thus, it is a composition of the list
and
flag
types.
-
env(options)
- An environment variable that the program is
interested in.
All environment variables will be present in the result
object. env()
can be composed with other types to change
how the environment variable is handled.
-
Compose with flag()
to define an environment variable that
is set to '1'
to mean true
, or '0'
or ''
to mean
false
. Presented in the result object as a boolean value.
For example:
jack({
FOO: env(flag({
description: 'Set to "1" to enable the foo flag'
}))
})
-
Compose with list()
to define an environment variable that
is set to multiple values separated by a delimiter. For
example:
jack({
NODE_DEBUG: env(list({
delimiter: ',',
description: 'Define which bits to debug'
}))
})
This can be further composed with num
to pass in a list
of numbers separated by a delimiter.
When composed with count
(which is the composition of
list
and flag
), you would pass in a delimited list of
1
and 0
characters, and it'd count up the 1
values.
I don't know why you'd ever do this, but it works.
-
Compose with num()
to parse the environ as a numeric
value, and raise an error if it is non-numeric.
Type Composition
Compose types by applying more than one function to the arg
definition options. For example, for a numeric environment
variable, you can do:
jack({
HOW_MANY_FOOS: env(num({
description: 'set to define the number of foos'
max: 10,
min: 2,
default: 5,
}))
})
The order of composition does not matter in normal cases, but note
that some compositions will contradict one another. For example,
composing flag
(an argument that does not take a value) with opt
(an argument that does take a value) will result in the outermost
function taking precedence.
Some Example Code
Also see the examples
folder
const { jack, flag, opt, list, count, num } = require('jackspeak')
jack({
main: myFunction,
argv: process.argv,
usage: 'foo [options] <files>',
help: `
Executes all the files and interprets their output as
TAP formatted test result data.
To parse TAP data from stdin, specify "-" as a filename.
`
flag: flag({
short: 'f',
description: `Make the flags wave`,
negate: {
short: 'F',
description: `Do not wave the flags`
},
default: true
}),
reporter: opt({
short: 'R',
description: 'the style of report to display',
})
jobs: num({
short: 'j',
description: 'how many jobs to run in parallel',
default: 1
}),
'jobs-auto': flag({
short: 'J',
alias: '--jobs=' + require('os').cpus().length
}),
timeout: num({
short: 't',
default: +process.env.TAP_TIMEOUT || 30,
}),
'no-timeout': flag({
short: 'T',
alias: '--timeout=0'
}),
'node-arg': list(),
debug: count({
short: 'd'
})
foo: flag({
alias: ['--statements=100', '--lines=100', '--branches=100'],
}),
covlevel: opt({
alias: [
'--statements=${value}',
'--lines=${value}',
'--branches=${value}'
]
}),
100: flag({
alias: '--covlevel=100'
}),
'output-file': opt({
short: 'o',
hint: 'file',
description: `Send the raw output to the specified file.`
}),
})
Name
The inspiration for this module is yargs, which
is pirate talk themed. Yargs has all the features, and is infinitely
flexible. "Jackspeak" is the slang of the royal navy. This module
does not have all the features. It is declarative and rigid by design.