npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

Iโ€™ve always been into building performant and accessible sites, but lately Iโ€™ve been taking it extremely seriously. So much so that Iโ€™ve been building a tool to help me optimize and monitor the sites that I build to make sure that Iโ€™m making an attempt to offer the best experience to those who visit them. If youโ€™re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, ๐Ÿ‘‹, Iโ€™m Ryan Hefnerย  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If youโ€™re interested in other things Iโ€™m working on, follow me on Twitter or check out the open source projects Iโ€™ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soonโ€“ish.

Open Software & Tools

This site wouldnโ€™t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you ๐Ÿ™

ยฉ 2024 โ€“ย Pkg Stats / Ryan Hefner

luminar

v0.0.5

Published

๐Ÿš€ A lightweight, powerful tool for parsing command-line arguments with ease.๐Ÿ‘Œ

Downloads

7

Readme

cover npm version npm downloads bundle JSDocs License

๐ŸŒ• luminar

๐Ÿš€ A lightweight, powerful tool for parsing command-line arguments with ease.๐Ÿ‘Œ

Note Luminar: Stands here symbolically for Flags. Luminar is based on the word, "lumen" (light) which symbolizes clarity and illumination. It indicates that this package provides transparency and understanding of the command line arguments.

โžก๏ธ Try it out online

Looking for something more robust? ๐Ÿ‘€

Try Zyro a CLI development tool powered by luminar.

In addition to luminar 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! ๐Ÿ’™

๐Ÿ“ฅ Install:

# nyxi
nyxi luminar

# pnpm
pnpm add luminar

# npm
npm i luminar

# yarn
yarn add luminar

โฑ๏ธ Quick start

luminar 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

๐Ÿ’ก typeLuminar

Here's how easy it is with luminar:

import { typeLuminar } from 'luminar'

const parsed = typeLuminar({
   name: String,
   age: {
      type: Number,
      alias: 'a'
   }
})

console.log(parsed.luminars.name) // 'John'
console.log(parsed.luminars.age) // 20

You can also get unknown luminars and arguments from the parsed object:

// object of unknown luminars passed in
console.log(parsed.unknownLuminars)

// arguments
console.log(parsed._)

๐Ÿ”ฆ getLuminar

Want something even simpler?

luminar also exports a getLuminar function that returns a single luminar value.

import { getLuminar } from 'luminar'

const name = getLuminar('--name', String)
const age = getLuminar('-a,--age', Number)

console.log(name) // 'John'
console.log(age) // 20

These are quick demos but ๐Ÿ”ฎ luminar can do so much more:

  • ๐Ÿ‘ฅ Accept multiple luminar values
  • โž• Luminar operators (e.g. =) for explicitly passing in a value
  • ๐Ÿงฉ Parse unknown luminars
  • ๐Ÿ”„ Parse alias groups (e.g. -abc)

Keep reading to learn more!

๐Ÿง‘โ€๐Ÿ’ป Usage

๐Ÿ’ก Defining luminars

Pass in an object where the key is the luminar name and the value is the luminar 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 luminar type.

typeLuminar({
   // Short-hand
   stringLuminar: String,
   numberLuminar: Number,
   booleanLuminar: Boolean,

   // Object syntax:
   stringLuminar: {
      type: String
   }
})

๐Ÿ“š Array type

To accept multiple values of a luminar, wrap the type with an array:

const parsed = typeLuminar({
   myLuminar: [String]
})

// $ node ./cli --my-luminar A --my-luminar B
parsed.luminars.myLuminar // => ['A', 'B']

๐ŸŽญ Aliases

Luminars are often given single-character aliases for shorthand usage (eg. --help to -h). To give a luminar an alias, use the object syntax and set the alias property to a single-character name.

typeLuminar({
   myLuminar: {
      type: String,
      alias: 'm'
   }
})

// $ node ./cli -m hello
parsed.luminars.myLuminar // => 'hello'

๐Ÿท๏ธ Default values

Luminars 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 = typeLuminar({
   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 luminar type, make sure strict or strictNullChecks is enabled.

๐Ÿฅ™ kebab-case luminars mapped to camelCase ๐Ÿซ

When passing in the luminars, they can be in kebab-case and will automatically map to the camelCase equivalent.

const parsed = typeLuminar({
   someString: [String]
})

// $ node ./cli --someString hello --some-string world
parsed.luminars.someString // => ['hello', 'world']

โ“ Unknown luminars

When unrecognized luminars are passed in, they are interpreted as a boolean, or a string if explicitly passed in. Unknown luminars are not converted to camelCase to allow for accurate error handling.

const parsed = typeLuminar({})

// $ node ./cli --some-luminar --some-luminar=1234
parsed.unknownLuminars // => { 'some-luminar': [true, '1234'] }

๐Ÿ“„ Arguments

Arguments are values passed in that are not associated with any luminars. All arguments are stored in the _ property.

Everything after -- (end-of-luminars) is treated as an argument (including luminars) and will be stored in the _['--'] property.

const parsed = typeLuminar({
   myLuminar: [String]
})

// $ node ./cli --my-luminar value arg1 -- --my-luminar world
parsed.luminars.myLuminar // => ['value']
parsed._ // => ['arg1', '--my-luminar', 'world']
parsed._['--'] // => ['--my-luminar', 'world']

๐ŸŒŸ Luminar value delimiters

The characters =, : and . are reserved for delimiting the value from the luminar.

$ node ./cli luminar=value luminar:value luminar.value

This allows for usage like --luminar:key=value or --luminar.property=value to be possible.

๐Ÿ”€ Mutated argv array

When luminar iterates over the argv array, it removes the tokens it parses out via mutation.

By default, luminar 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 luminars and arguments, you can pass in your own copy of process.argv.slice(2).

This may be useful for filtering out certain luminars before passing down the argv to a child process.

๐Ÿšซ Ignoring unknown luminars

Sometimes it may be undesirable to parse unknown luminars. In these cases, you can ignore them so they're left unparsed in the argv array.

const argv = process.argv.slice(2)
const parsed = typeLuminar(
   {},
   argv,
   {
      ignore: type => type === 'unknown-luminar'
   }
)

// $ node ./cli --unknown=hello
parsed._ // => []
argv // => ['--unknown=hello']

๐Ÿ›‘ Ignoring everything after the first argument

Similarly to how Node.js only reads luminars passed in before the first argument, luminar can be configured to ignore everything after the first argument.

const argv = process.argv.slice(2)

let stopParsing = false
const parsed = typeLuminar(
   {
      myLuminar: [Boolean]
   },
   argv,
   {
      ignore(type) {
         if (stopParsing)
            return true

         const isArgument = type === 'argument'
         if (isArgument) {
            stopParsing = isArgument
            return stopParsing
         }
      }
   }
)

// $ node ./cli --my-luminar ./file.js --my-luminar
parsed.luminars.myLuminar // => [true]
argv // => ['./file.js', '--my-luminar']

๐Ÿ‘จ๐Ÿปโ€๐Ÿซ Examples

โš™๏ธ Custom luminar type

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 luminar 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 = typeLuminar({
   size: Size
})

parsed resolves to the following type:

interface Parsed {
   luminars: {
      size: 'small' | 'medium' | 'large' | undefined
   }
   // ...
}

๐Ÿ”„ Optional value luminar

To create a string luminar 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 = typeLuminar({
   string: OptionalString
})

// $ node ./cli --string
parsed.luminars.string // => true

// $ node ./cli --string hello
parsed.luminars.string // => 'hello'

โšก๏ธ Accepting luminar values with = in it

In use-cases where luminar values contain =, you can use : instead. This allows luminars like --define:K=V.

const parsed = typeLuminar({
   define: String
})

// $ node ./cli --define:key=value
parsed.luminars.define // => 'key=value'

๐ŸŒณ Dot-nested luminars

interface Environment {
   TOKEN?: string
   CI?: boolean
}

function EnvironmentObject(value: string): Environment {
   const [propertyName, propertyValue] = value.split('=')
   return {
      [propertyName]: propertyValue || true
   }
}

const parsed = typeLuminar({
   env: [EnvironmentObject]
})

const env = parsed.luminars.env.reduce(
   (agg, next) => Object.assign(agg, next),
   {}
)

// $ node ./cli --env.TOKEN=123 --env.CI
env // => { TOKEN: 123, CI: true }

๐Ÿ” Inverting a boolean

To invert a boolean luminar, false must be passed in with the = operator (or any other value delimiters).

const parsed = typeLuminar({
   booleanLuminar: Boolean
})

// $ node ./cli --boolean-luminar=false
parsed.luminars.booleanLuminar // => false

Without explicitly specfying the luminar value via =, the false will be parsed as a separate argument.

// $ node ./cli --boolean-luminar false
parsed.luminars.booleanLuminar // => true
parsed._ // => ['false']

๐Ÿ”ข Counting luminars

To create an API where passing in a luminar 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 = typeLuminar({
   verbose: {
      type: [Boolean],
      alias: 'v'
   }
})

// $ node ./cli -vvv
parsed.luminars.verbose.length // => 3

โš™๏ธ API

๐Ÿ’ก typeLuminar(luminarSchema, argv, options)

Returns an object with the shape:

interface Parsed {
   luminars: {
      [luminarName: string]: InferredType
   }
   unknownLuminars: {
      [luminarName: string]: (string | boolean)[]
   }
   _: string[]
}

๐Ÿ“‹ luminarSchema

Type:

type TypeFunction = (argvValue: any) => any

interface LuminarSchema {
   [luminarName: string]: TypeFunction | [TypeFunction] | {
      type: TypeFunction | [TypeFunction]
      alias?: string
      default?: any
   }
}

An object containing luminar schema definitions. Where the key is the luminar name, and the value is either the type function or an object containing the type function and/or alias.

๐Ÿ“„ argv

Type: string[]

Default: process.argv.slice(2)

The argv array to parse. The array is mutated to remove the parsed luminars.

โš™๏ธ options

Type:

interface Options {
   // Callback to skip parsing on certain argv tokens
   ignore?: (
      type: 'known-luminar' | 'unknown-luminar' | 'argument',
      luminarOrArgv: string,
      value: string | undefined,
   ) => boolean | void
}

๐Ÿ”ฆ getLuminar(luminarNames, luminarType, argv)

๐Ÿ“‹ luminarNames

Type: string

A comma-separated list of luminar names to parse.

๐ŸŒŸ luminarType

Type:

type TypeFunction = (argvValue: any) => any

type LuminarType = TypeFunction | [TypeFunction]

A function to parse the luminar value. Wrap the function in an array to retrieve all values.

๐Ÿ“„ argv

Type: string[]

Default: process.argv.slice(2)

The argv array to parse. The array is mutated to remove the parsed luminars.

๐Ÿ“œ License

MIT - Made with ๐Ÿ’ž