Skip to content

munesoft/flagx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@munesoft/flagx

Tiny CLI flag utility with superpowers. A has-flag alternative that actually grows with your needs.

npm version zero dependencies size license


What is flagx?

flagx is a modern Node.js argv parser — a cli flag parser and has-flag alternative — designed to be the last flag utility you'll ever need. It's tiny, fast, and zero-dependency, but covers everything from simple boolean checks to advanced grouped flags, aliasing, type inference, and validation.

Most tools are either too simple (has-flag — booleans only) or too heavy (minimist, yargs — full parsers with baggage). flagx sits in the middle: a tiny utility that punches way above its weight class.

Simple boolean check?       → One line.
Need a port number?         → One line.
DB config group?            → One line.
Light validation?           → One line.

Why flagx?

Feature has-flag minimist flagx
Boolean flags
Value extraction
Type inference
Aliases
Glob pattern matching
Flag grouping
Merge env/config
Lazy + cached parse
Light validation
Zero dependencies
Bundle size ~0.1KB ~3KB <2KB

Quick Start

npm install @munesoft/flagx
import flagx from "@munesoft/flagx";

// That's it. One line.
if (flagx("debug")) {
  console.log("debug mode on");
}

Works with all standard flag styles out of the box:

node app.js --debug --port=3000 --no-verbose -f -abc

Examples

Boolean check (the has-flag replacement)

import flagx from "@munesoft/flagx";

flagx("debug");     // true/false
flagx("verbose");   // true/false
flagx("prod");      // true/false

Get a value with default

const port = flagx.value("port", 3000);
const host = flagx.value("host", "localhost");

Transform on read

const port = flagx.value("port", Number);         // → always a number
const tags = flagx.value("tag", v => v.split(",")); // → array from string

Aliases

flagx.alias({ p: "port", v: "verbose", h: "host" });

// Now -p 3000 and --port=3000 both work
const port = flagx.value("port");

Pick multiple flags at once

const { port, host, debug } = flagx.pick(["port", "host", "debug"]);

Multi-flag logic

flagx.hasAny(["debug", "verbose"]);    // at least one
flagx.hasAll(["port", "host"]);        // all required

Glob pattern matching

// Flag: --db.host=localhost --db.port=5432 --db.ssl=true
const dbFlags = flagx.match("db.*");
// → { "db.host": "localhost", "db.port": 5432, "db.ssl": true }

Grouping

// Flag: --db.host=localhost --db.port=5432
const db = flagx.group("db");
// → { host: "localhost", port: 5432 }

// Perfect for connecting to a database:
const client = new DB(db);

Merge env vars or config

flagx.merge({
  env: process.env,
  config: { port: 3000, host: "localhost" },
});

// CLI flags always win. Env and config fill in gaps.
const port = flagx.value("port"); // from CLI, env, or config

Light validation

flagx.expect({
  port: "number",
  debug: "boolean",
  name: "string",
});
// Warns on type mismatch, throws in strict mode

Strict mode

const fx = flagx({ strict: true });
fx.expect({ port: "number" }); // throws if wrong type

Command detection

// $ node cli.js build --watch
const cmd = flagx.command(); // → "build"

Flag metadata

const meta = flagx.meta("port");
// → { exists: true, value: 3000, index: 0, raw: "--port=3000" }

Debug output (dev tool)

flagx.debug();
// [flagx debug] Parsed flags:
//   --port                 3000                 (number)
//   --debug                true                 (boolean)

JSON output (AI-friendly)

console.log(flagx.json());
// { "port": 3000, "debug": true }

API Reference

flagx(name): boolean

Check whether a flag is present and truthy. The core has-flag-style API.

flagx("debug"); // true/false

flagx(options): api

Configure the instance. Currently supports { strict: boolean }.

flagx({ strict: true });

flagx.value(name, defaultOrTransform?): any

Get a flag's value. Pass a default value or a transform function as the second argument.

flagx.value("port");              // raw value or undefined
flagx.value("port", 3000);        // with default
flagx.value("port", Number);      // transform: coerce to number
flagx.value("host", v => `http://${v}`); // arbitrary transform

flagx.pick(keys[]): object

Extract multiple flags at once.

flagx.pick(["port", "host", "debug"]);
// → { port: 3000, host: "localhost", debug: true }

flagx.all(): object

Return all parsed flags as a plain object.

flagx.all(); // → { port: 3000, debug: true, ... }

flagx.hasAny(keys[]): boolean

Returns true if at least one of the keys is present and truthy.


flagx.hasAll(keys[]): boolean

Returns true only if all keys are present and truthy.


flagx.match(pattern): object

Return all flags matching a glob-style pattern (* wildcard).

flagx.match("db.*");     // → all --db.x flags
flagx.match("--no-*");   // → all negated flags

flagx.group(prefix): object

Return all flags under a prefix, with the prefix stripped from keys.

// --db.host=localhost --db.port=5432
flagx.group("db"); // → { host: "localhost", port: 5432 }

flagx.meta(name): object

Return metadata about a flag.

flagx.meta("port");
// → { exists: true, value: 3000, index: 0, raw: "--port=3000" }

flagx.alias(map): api

Register short-to-long aliases. Chainable.

flagx.alias({ p: "port", v: "verbose" });

flagx.merge(sources): api

Merge additional flag sources. CLI args always take precedence.

flagx.merge({ env: process.env, config: loadConfig() });

flagx.expect(schema): boolean

Validate flag types. Warns by default; throws in strict mode.

flagx.expect({ port: "number", debug: "boolean" });

Supported types: "boolean", "number", "string", "array"


flagx.command(): string | undefined

Returns the first positional argument (typically a subcommand).


flagx.positionals(): string[]

Returns all non-flag positional arguments.


flagx.raw(): string[]

Returns the raw argv slice (everything after node script.js).


flagx.debug(): api

Prints all parsed flags with types to stdout. Dev-only tool.


flagx.json(): string

Returns all flags as a formatted JSON string.


flagx.from(argv[]): api

Override the argv source. Useful for testing.

flagx.from(["--port=3000", "--debug"]);

flagx.reset(): api

Reset all state including aliases, merges, and cache.


Parsing Rules

flagx supports every common CLI flag syntax:

Input Result
--flag true
--flag=true true (boolean)
--flag=false false (boolean)
--no-flag false
--key=value "value" (string)
--port=3000 3000 (number)
-f true
-abc a=true, b=true, c=true
-p 3000 p=3000
--flag --flag [true, true] (array)
-- stop parsing (rest → positionals)

Note on space-separated values: For long flags (--key value), flagx only greedily consumes the next token when it's a typed value (number or boolean). For string values, use --key=value syntax. Short flags (-p value) always consume the next token.


Performance

flagx is built around two core principles:

Lazy parsing — argv is never touched until the first API call.

Single parse — the result is cached after the first call. Every subsequent call — flagx("x"), flagx.value("y"), flagx.all() — uses the same cached object.

100 × 1000-flag parses:   ~38ms
Cached access:            ~0ms

This makes flagx safe to call anywhere — top of a file, in hot paths, conditionally — with no performance penalty.


Comparison

vs has-flag

has-flag does one thing: checks if a flag string exists in process.argv. No values, no types, no aliases. flagx replaces it with a superset that's still a one-liner.

vs minimist

minimist is a capable parser but is heavier (~3KB), older, and doesn't offer grouping, pattern matching, lazy parsing, merge sources, or built-in validation. flagx weighs less and does more.

vs yargs/commander

These are full CLI frameworks: help generation, command routing, middleware. If you're building a complex CLI application, they're worth it. If you just need to read flags in a script, a library, or a build tool, flagx is the right weight.


FAQ

Does flagx work in CommonJS? Currently ESM-only (type: "module"). A CJS build can be added if needed.

Does it handle process.argv automatically? Yes. By default it reads process.argv.slice(2). Use flagx.from([...]) to override.

Can I use it in a library (not a CLI)? Yes. Use flagx.from(argv) with a passed-in array rather than process.argv.

Is the parse result mutable? flagx.all() returns a shallow copy. The internal cache is not exposed directly.

What about Windows-style /flag syntax? Not supported — flagx follows the POSIX/GNU convention used by Node.js ecosystem tools.


Keywords

cli flag parser · nodejs argv parser · command line flags javascript · has-flag alternative · minimist alternative · argv · cli · flags · parse · args


License

MIT © Munesoft

About

Tiny CLI flag utility with superpowers. Zero deps, lazy parsing, type inference, aliases, grouping and more.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors