![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Typed command-line arguments parser. Only 1.4 kB.
Looking for something more robust? 👀
Try Cleye—a CLI development tool powered by type-flag.
In addition to flag parsing, it supports argument parsing and has a beautiful
--help
documentation generator.
Support this project by ⭐️ starring and sharing it. Follow me to see what other cool projects I'm working on! ❤️
npm i type-flag
type-flag offers a simple API to parse command-line arguments.
Let's say you want to create a script with the following usage:
$ my-script --name John --age 20
Here's how easy it is with type-flag:
import { typeFlag } from 'type-flag'
const parsed = typeFlag({
name: String,
age: {
type: Number,
alias: 'a'
}
})
console.log(parsed.flags.name) // 'John'
console.log(parsed.flags.age) // 20
You can also get unknown flags and arguments from the parsed
object:
// object of unknown flags passed in
console.log(parsed.unknownFlags)
// arguments
console.log(parsed._)
Want something even simpler?
type-flag also exports a getFlag
function that returns a single flag value.
import { getFlag } from 'type-flag'
const name = getFlag('--name', String)
const age = getFlag('-a,--age', Number)
console.log(name) // 'John'
console.log(age) // 20
These are quick demos but type-flag can do so much more:
=
) for explicitly passing in a value-abc
)Keep reading to learn more!
Pass in an object where the key is the flag name and the value is the flag type—a parser function that takes in a string and parses it to that type. Default JavaScript constructors should be able to cover most use-cases: String, Number, Boolean, etc.
The value can also be an object with the type
property as the flag type.
typeFlag({
// Short-hand
stringFlag: String,
numberFlag: Number,
booleanFlag: Boolean,
// Object syntax:
stringFlag: {
type: String
}
})
To accept multiple values of a flag, wrap the type with an array:
const parsed = typeFlag({
myFlag: [String]
})
// $ node ./cli --my-flag A --my-flag B
parsed.flags.myFlag // => ['A', 'B']
Flags are often given single-character aliases for shorthand usage (eg. --help
to -h
). To give a flag an alias, use the object syntax and set the alias
property to a single-character name.
typeFlag({
myFlag: {
type: String,
alias: 'm'
}
})
// $ node ./cli -m hello
parsed.flags.myFlag // => 'hello'
Flags that are not passed in will default to being undefined
. To set a different default value, use the object syntax and pass in a value as the default
property. When a default is provided, the return type will reflect that instead of undefined
.
When using mutable values (eg. objects/arrays) as a default, pass in a function that creates it to avoid mutation-related bugs.
const parsed = typeFlag({
someNumber: {
type: Number,
default: 1
},
manyNumbers: {
type: [Number],
// Use a function to return an object or array
default: () => [1, 2, 3]
}
})
To get undefined
in the parsed flag type, make sure strict
or strictNullChecks
is enabled.
When passing in the flags, they can be in kebab-case and will automatically map to the camelCase equivalent.
const parsed = typeFlag({
someString: [String]
})
// $ node ./cli --someString hello --some-string world
parsed.flags.someString // => ['hello', 'world']
When unrecognized flags are passed in, they are interpreted as a boolean, or a string if explicitly passed in. Unknown flags are not converted to camelCase to allow for accurate error handling.
const parsed = typeFlag({})
// $ node ./cli --some-flag --some-flag=1234
parsed.unknownFlags // => { 'some-flag': [true, '1234'] }
Arguments are values passed in that are not associated with any flags. All arguments are stored in the _
property.
Everything after --
(end-of-flags) is treated as an argument (including flags) and will be stored in the _['--']
property.
const parsed = typeFlag({
myFlag: [String]
})
// $ node ./cli --my-flag value arg1 -- --my-flag world
parsed.flags.myFlag // => ['value']
parsed._ // => ['arg1', '--my-flag', 'world']
parsed._['--'] // => ['--my-flag', 'world']
The characters =
, :
and .
are reserved for delimiting the value from the flag.
$ node ./cli --flag=value --flag:value --flag.value
This allows for usage like --flag:key=value
or --flag.property=value
to be possible.
When type-flag
iterates over the argv array, it removes the tokens it parses out via mutation.
By default, type-flag
works on a new copy of process.argv.slice(2)
so this doesn't have any side-effects. But if you want to leverage this behavior to extract certain flags and arguments, you can pass in your own copy of process.argv.slice(2)
.
This may be useful for filtering out certain flags before passing down the argv
to a child process.
Sometimes it may be undesirable to parse unknown flags. In these cases, you can ignore them so they're left unparsed in the argv
array.
const argv = process.argv.slice(2)
const parsed = typeFlag(
{},
argv,
{
ignore: type => type === 'unknown-flag'
}
)
// $ node ./cli --unknown=hello
parsed._ // => []
argv // => ['--unknown=hello']
Similarly to how Node.js only reads flags passed in before the first argument, type-flag can be configured to ignore everything after the first argument.
const argv = process.argv.slice(2)
let stopParsing = false
const parsed = typeFlag(
{
myFlag: [Boolean]
},
argv,
{
ignore(type) {
if (stopParsing) {
return true
}
const isArgument = type === 'argument'
if (isArgument) {
stopParsing = isArgument
return stopParsing
}
}
}
)
// $ node ./cli --my-flag ./file.js --my-flag
parsed.flags.myFlag // => [true]
argv // => ['./file.js', '--my-flag']
Basic types can be set using built-in functions in JavaScript, but sometimes you want to a new type, narrow the type, or add validation.
To create a new type, simply declare a function that accepts a string argument and returns the parsed value with the expected type.
In this example, the size
flag is enforced to be either small
, medium
or large
.
const possibleSizes = ['small', 'medium', 'large'] as const
type Sizes = typeof possibleSizes[number]
function Size(size: Sizes) {
if (!possibleSizes.includes(size)) {
throw new Error(`Invalid size: "${size}"`)
}
return size
}
const parsed = typeFlag({
size: Size
})
parsed
resolves to the following type:
type Parsed = {
flags: {
size: 'small' | 'medium' | 'large' | undefined
}
// ...
}
To create a string flag that acts as a boolean when nothing is passed in, create a custom type that returns both types.
function OptionalString(value: string) {
if (!value) {
return true
}
return value
}
const parsed = typeFlag({
string: OptionalString
})
// $ node ./cli --string
parsed.flags.string // => true
// $ node ./cli --string hello
parsed.flags.string // => 'hello'
=
in itIn use-cases where flag values contain =
, you can use :
instead. This allows flags like --define:K=V
.
const parsed = typeFlag({
define: String
})
// $ node ./cli --define:key=value
parsed.flags.define // => 'key=value'
type Environment = {
TOKEN?: string
CI?: boolean
}
function EnvironmentObject(value: string): Environment {
const [propertyName, propertyValue] = value.split('=')
return {
[propertyName]: propertyValue || true
}
}
const parsed = typeFlag({
env: [EnvironmentObject]
})
const env = parsed.flags.env.reduce(
(agg, next) => Object.assign(agg, next),
{}
)
// $ node ./cli --env.TOKEN=123 --env.CI
env // => { TOKEN: 123, CI: true }
To invert a boolean flag, false
must be passed in with the =
operator (or any other value delimiters).
const parsed = typeFlag({
booleanFlag: Boolean
})
// $ node ./cli --boolean-flag=false
parsed.flags.booleanFlag // => false
Without explicitly specfying the flag value via =
, the false
will be parsed as a separate argument.
// $ node ./cli --boolean-flag false
parsed.flags.booleanFlag // => true
parsed._ // => ['false']
To create an API where passing in a flag multiple times increases a count (a pretty common one is -vvv
), you can use an array-boolean type and count the size of the array:
const parsed = typeFlag({
verbose: {
type: [Boolean],
alias: 'v'
}
})
// $ node ./cli -vvv
parsed.flags.verbose.length // => 3
Returns an object with the shape:
type Parsed = {
flags: {
[flagName: string]: InferredType
}
unknownFlags: {
[flagName: string]: (string | boolean)[]
}
_: string[]
}
Type:
type TypeFunction = (argvValue: any) => any
type FlagSchema = {
[flagName: string]: TypeFunction | [TypeFunction] | {
type: TypeFunction | [TypeFunction]
alias?: string
default?: any
}
}
An object containing flag schema definitions. Where the key is the flag name, and the value is either the type function or an object containing the type function and/or alias.
Type: string[]
Default: process.argv.slice(2)
The argv array to parse. The array is mutated to remove the parsed flags.
Type:
type Options = {
// Callback to skip parsing on certain argv tokens
ignore?: (
type: 'known-flag' | 'unknown-flag' | 'argument',
flagOrArgv: string,
value: string | undefined,
) => boolean | void
}
Type: string
A comma-separated list of flag names to parse.
Type:
type TypeFunction = (argvValue: any) => any
type FlagType = TypeFunction | [TypeFunction]
A function to parse the flag value. Wrap the function in an array to retrieve all values.
Type: string[]
Default: process.argv.slice(2)
The argv array to parse. The array is mutated to remove the parsed flags.
FAQs
Typed command-line arguments parser
The npm package type-flag receives a total of 8,739 weekly downloads. As such, type-flag popularity was classified as popular.
We found that type-flag demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.