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 🙏

© 2026 – Pkg Stats / Ryan Hefner

haggis

v1.0.3

Published

Read argv based on object template

Readme

haggis

A simple, template-based command-line argument parser for Node.js that makes working with argv intuitive and type-safe.

What Does This Package Do?

When you run a program from the command line with arguments like this:

node myapp.js -s file1.js file2.js -d /output --exclude

Your program receives these arguments as an array of strings. haggis transforms this array into a structured object based on a template you provide, automatically handling:

  • Short flags (-e, -s)
  • Long flags (--exclude, --source)
  • Multiple values for the same option
  • Type casting (strings, numbers, booleans)
  • Positional arguments (arguments without flags)

Installation

npm install haggis

Quick Start

import { argv } from 'node:process';
import haggis from 'haggis';

// Define your template
const template = {
  exclude: false,
  source: [],
  destination: "",
};

// Optional configuration
const options = {
  strict: true,        // Only accept flags defined in template
  initial: 'source',   // Default property for positional arguments
};

const result = haggis(template, options, argv);
console.log(result);

Running it:

node myapp.js file1.js file2.js -d /output -e

Result:

{
  exclude: true,
  source: ['file1.js', 'file2.js'],
  destination: '/output'
}

How It Works

The Template Object

The template defines what arguments your program accepts and their default values:

const template = {
  exclude: false,      // Boolean flag, defaults to false
  source: [],          // Array to collect multiple values
  destination: "",     // String value
  count: 0,           // Number value
};

The type of each property determines how haggis handles the values:

  • false → Boolean flags (presence = true)
  • [] → Arrays that collect multiple values
  • "" → Strings (takes the last value if multiple provided)
  • 0 → Numbers (automatically converted)

Short vs Long Flags

Short flags start with a single dash (-) and use the first letter of your template property:

-e        # matches 'exclude'
-s        # matches 'source'
-d        # matches 'destination'

You can combine short flags:

-ed       # equivalent to -e -d

Long flags start with double dashes (--) and use the full property name:

--exclude
--source
--destination

Positional Arguments

Arguments without flags are called "positional arguments." The initial option tells haggis which template property should receive them:

const options = {
  initial: 'source',  // Positional args go to 'source'
};
node myapp.js file1.js file2.js    # Both files go to 'source'

Understanding Quotes in UNIX/Linux

For beginners: When you type commands in a terminal, the shell (bash, zsh, etc.) processes your input before passing it to your program. Understanding how quotes work is essential.

How the Shell Handles Quotes

In UNIX/Linux shells, quotes control how arguments are split and interpreted:

Without Quotes

Spaces separate arguments:

node myapp.js hello world
# argv = ['node', 'myapp.js', 'hello', 'world']
# Two separate arguments

With Double Quotes ("")

Everything inside is treated as one argument, but the shell still processes:

  • Variable expansion ($VAR becomes its value)
  • Command substitution (`command` or $(command))
  • Escape sequences (\n, \t)
node myapp.js "hello world"
# argv = ['node', 'myapp.js', 'hello world']
# One argument with a space

node myapp.js "Hello $USER"
# If USER=john, argv = ['node', 'myapp.js', 'Hello john']

With Single Quotes ('')

Everything inside is treated literally - no expansion happens:

node myapp.js 'hello world'
# argv = ['node', 'myapp.js', 'hello world']
# One argument with a space

node myapp.js 'Hello $USER'
# argv = ['node', 'myapp.js', 'Hello $USER']
# The $USER is NOT expanded

Important: By the Time Your Program Runs

The quotes are already removed! The shell processes them and removes them before your program sees the arguments. Your Node.js program receives the processed strings, not the quotes themselves.

node myapp.js "my file.txt"
# Your program receives: ['node', 'myapp.js', 'my file.txt']
# The quotes are gone - you just get the string with a space in it

This means haggis (and your program) never sees the quotes - it only sees the final string values that the shell provides.

Practical Examples

# Filename with spaces - NEEDS quotes
node myapp.js -s "my document.txt" -d "/output folder"

# Without quotes (WRONG - treated as 4 separate arguments)
node myapp.js -s my document.txt -d /output folder
# source = ['my']
# destination = 'document.txt'
# And 'folder' might be treated as a positional argument!

# Using variables
node myapp.js -d "$HOME/output"     # Expands to /home/yourname/output
node myapp.js -d '$HOME/output'     # Literally the string: $HOME/output

# Special characters that need quotes
node myapp.js "file with * and ?" 
# Without quotes, * and ? are wildcards expanded by the shell

Options

strict (default: true)

When true, haggis ignores flags that aren't defined in your template:

const options = { strict: true };

// Template only has 'source' and 'destination'
// Running: node myapp.js --unknown value
// The --unknown flag is ignored

When false, unknown flags are allowed (but not added to the result).

initial (default: 'positional')

Specifies which template property receives positional arguments:

const options = { initial: 'source' };

// Running: node myapp.js file1.js file2.js
// Both files go to result.source

Automatic Type Casting

haggis automatically converts string arguments to appropriate types:

// Running: node myapp.js --count 42 --enabled true --ratio 3.14

// Result:
{
  count: 42,        // Number (integer)
  enabled: true,    // Boolean
  ratio: 3.14       // Number (float)
}

Conversion rules:

  • "true" / "false" → Boolean
  • Numeric strings → Numbers (integers or floats)
  • Everything else → String
  • Empty/whitespace → null

Complete Example

import { argv } from 'node:process';
import haggis from 'haggis';

const template = {
  verbose: false,
  input: [],
  output: "",
  threads: 1,
};

const options = {
  strict: true,
  initial: 'input',
};

const config = haggis(template, options, argv);

if (config.verbose) {
  console.log('Input files:', config.input);
  console.log('Output directory:', config.output);
  console.log('Thread count:', config.threads);
}

Usage:

# Basic usage
node process.js file1.js file2.js -o /output

# With all options
node process.js file1.js file2.js --output /output --threads 4 -v

# Using quotes for paths with spaces
node process.js "my file.js" "another file.js" -o "/output folder" -v

API

haggis(template, options, argv)

Parameters:

  • template (Object): Object defining accepted arguments and their default values
  • options (Object): Configuration object
    • strict (Boolean): Only accept flags defined in template (default: true)
    • initial (String): Property name for positional arguments (default: 'positional')
  • argv (Array): Process arguments array (typically process.argv)

Returns: Object with parsed arguments based on template structure

Running Tests

npm test

License

MIT

Author

@catpea

Repository

https://github.com/catpea/haggis