Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@benev/argv

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@benev/argv

command line argument parser

  • 0.2.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
147
decreased by-33.78%
Maintainers
1
Weekly downloads
 
Created
Source

🎛️ @benev/argv

the first great command line parser for typescript, maybe

🤖 for making node cli programs
🕵️ incredible typescript type inference
🧼 zero dependencies
💖 made free and open source, just for you


autogenerated --help pages

pizza --help

pizza large --pepperoni --slices 3

# or, any way you like it
pizza --slice=9 large
pizza medium -p --slice=5
pizza small --pepperoni="no" --slice="2"

getting started

  1. install @benev/argv via npm
    npm i @benev/argv
    
  2. import stuff
    import {cli, command, arg, param} from "@benev/argv"
    
  3. specify your cli, and perform the parsing
    const {args, params} = cli(process.argv, {
      name: "pizza",
      commands: command({
        args: [
          arg("size").required(String),
        ],
        params: {
          slices: param.default(Number, {fallback: 1}),
          pepperoni: param.flag("p"),
        },
      }),
    }).tree
    
  4. now you have your args and params
    args.size // "large"
    params.slices // 5
    params.pepperoni // true
    
    • this is the "flat strategy" for receiving your args and params. simple, easy!
  5. all your types automagically work!
    it took me a long time to make it elegant and cool like this.

tree of multiple commands

  • the commands object is a recursive tree with command leaves
    const {tree} = cli(process.argv, {
      name: "converter",
      commands: {
        image: command({
          args: [],
          params: {
            quality: param.required(Number),
          },
        }),
        media: {
          audio: command({
            args: [],
            params: {
              mono: param.required(Boolean),
            },
          }),
          video: command({
            args: [],
            params: {
              codec: param.required(String),
            },
          })
        },
      },
    })
    
  • you get this tree object that reflects its shape
    tree.image?.params.quality // 9
    tree.media.audio?.mono // false
    tree.media.video?.codec // "av1"
    
    • all the commands are undefined except for the "selected" command
    • and yes, all the typings work

command-execution strategy

  • you can choose to provide each command with an async execute function
    command({
      args: [],
      params: {
        active: param.required(Boolean),
        count: param.default(Number, {fallback: 101}),
      },
      async execute({params}) {
        params.active // true
        params.count // 101
      },
    })
    
    • your execute function receives fully-typed args, params, and some more stuff
  • if you choose to use this command-execution strategy, then you need to call your cli's final execute function
    // 👇 awaiting cli execution
    await cli(process.argv, {
      name: "pizza",
      commands: {
        meatlovers: command({
          args: [],
          params: {
            meatiness: param.required(Number),
          },
          async execute({params}) {
            console.log(params.meatiness) // 9
          },
        }),
        hawaiian: command({
          args: [],
          params: {
            pineappleyness: param.required(Number),
          },
          async execute({params}) {
            console.log(params.pineappleyness) // 8
          },
        }),
      },
    }).execute()
      // ☝️ calling cli final execute
    

so you get these handy helpers

command, arg, and param

  • let's start by making a command
    command({
      args: [],
      params: {},
    })
    
  • a command can optionally accept a help string
    command({
      help: "what a time to be alive!",
      args: [],
      params: {},
    })
    
  • let's add positional args
    command({
      args: [
        arg("active").required(Boolean),
        arg("count").default(Number, {fallback: 101}),
        arg("name").optional(String),
      ],
      params: {},
    })
    
    • args are in an array, so each needs a name, eg "active" above
    • so we're flexing required, default, and optional
    • default requires a fallback value
    • there are three possible primitives: Boolean, Number, or String
  • now let's talk about params
    command({
      args: [],
      params: {
        active: param.required(Boolean),
        count: param.default(Number, {fallback: 101}),
        name: param.optional(String),
        verbose: param.flag("-v"),
      },
    })
    
    • pretty similar. but see the way the names are different?
    • there's a new variety of param called flag, of course, it's automatically a Boolean (how could it be otherwise?)

validation for args and params

  • you can set a validate function on any arg or param
    arg("quality").optional(Number, {
      validate: n => {
        if (n > 100) throw new Error("to big")
        if (n < 0) throw new Error("to smol")
        return n
      },
    })
    
    • if you throw any error in a validate, it will be printed all nice-like to the user

help literally everywhere

  • in fact, every arg and param can have its own help
    command({
      help: "it's the best command, nobody makes commands like me",
    
      args: [
        arg("active").required(Boolean, {
          help: "all systems go?",
        }),
    
        arg("count").default(Number, {
          fallback: 101,
          help: "number of dalmatians",
        }),
    
        arg("name").optional(String, {help: `
          see this multi-line string?
          it will be trimmed all nicely on the help page.
        `}),
      ],
    
      params: {
        active: param.required(Boolean, {
          help: "toggle this carefully!",
        }),
    
        count: param.default(Number, {
          fallback: 101,
          help: "classroom i'm late for",
        }),
    
        name: param.optional(String, {
          help: "pick your pseudonym",
        }),
    
        verbose: param.flag("-v", {
          help: "going loud",
        }),
      },
    })
    

choice helper

  • you can use the choice helper to set up a multiple choice string
    arg("crust").required(String, choice(["thick", "thin"]))
    
  • you can add a help to it as well
    arg("crust").required(String, choice(["thick", "thin"], {
      help: "made with organic whole-wheat flour",
    }))
    

🌠 give me a github star

  • i worked way too hard on this

Keywords

FAQs

Package last updated on 22 May 2024

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc