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 🙏

© 2025 – Pkg Stats / Ryan Hefner

yargs-file-commands

v0.0.20

Published

A yargs helper function that lets you define your commands structure via directory and file naming conventions.

Readme

Yargs File Commands

NPM Package NPM Downloads

This Yargs helper function lets you define all your commands as individual files and their file names and directory structure defines via implication your nested command structure.

Supports both JavaScript and TypeScript (on Node 22+.)

Installation

NOTE: This is an ESM-only package.

npm install yargs-file-commands

Example

export const main = async () => {
  const commandsDir = path.join(distDir, 'commands');

  return yargs(hideBin(process.argv))
    .scriptName(packageInfo.name!)
    .version(packageInfo.version!)
    .command(
      await fileCommands({ commandDirs: [commandsDir], logLevel: 'debug' })
    )
    .help().argv;
};

You can use any combination of file names and directories. We support either NextJS or Remix conventions for interpreting filenames and directories.

/commands
├── db
│   ├── migration
│   │   └── command.ts // the "db migration" command
│   └── health.ts      // the "db health" command
├── $default.ts        // the default command
└── studio.start.ts    // the "studio start" command

Inside each route handler file, you define your command configuration. The command name defaults to the filename, but you can explicitly specify it using the command export to support positional arguments. Here are some examples:

// commands/studio.start.ts - Basic command using filename as command name

import type { ArgumentsCamelCase, Argv } from 'yargs';
import type { BaseOptions } from '../options.js';

export interface Options extends BaseOptions {
  port?: number;
}

export const command = 'start'; // this is optional, it will use the filename if this isn't specified

export const describe = 'Studio web interface';

export const builder = (args: Argv): Argv<Options> => {
  const result = args.option('port', {
    alias: 'p',
    type: 'number',
    describe: 'Port to listen on'
  });
  return result;
};

export const handler = async (args: ArgumentsCamelCase<Options>) => {
  const config = await getConfig();
  // Implementation
};
// Command with positional arguments

export const command = 'create [name]';
export const describe = 'Create a new migration';

export const builder = (args: Argv): Argv<Options> => {
  return args.positional('name', {
    describe: 'Name of the migration',
    type: 'string',
    demandOption: true
  });
};

export const handler = async (args: ArgumentsCamelCase<Options>) => {
  // Implementation
};
// Must be named $default.ts - Default command (runs when no command is specified)

export const describe = 'Default command';

export const handler = async (args: ArgumentsCamelCase<Options>) => {
  console.log('Running default command');
};

The above will result in these commands being registered:

db migration
db health
studio start

Alternative Type-Safe Command Definition

YOu can also use this type-safe way to define commands using the CommandModule type from yargs directly. This is the preferred method as it provides better TypeScript support and catches potential errors at compile time rather than runtime:

import type { ArgumentsCamelCase, CommandModule } from 'yargs';

type TriageArgs = {
  owner: string;
  repo: string;
  issue: number;
};

export const command: CommandModule<object, TriageArgs> = {
  command: 'triage <owner> <repo> <issue>',
  describe: 'Triage a GitHub issue',
  builder: {
    owner: {
      type: 'string',
      description: 'GitHub repository owner',
      demandOption: true
    },
    repo: {
      type: 'string',
      description: 'GitHub repository name',
      demandOption: true
    },
    issue: {
      type: 'number',
      description: 'Issue number',
      demandOption: true
    }
  },
  handler: async (argv: ArgumentsCamelCase<TriageArgs>) => {
    // Implementation
  }
};

This approach has several advantages:

  • Full TypeScript support with proper type inference
  • Compile-time checking of command structure
  • No risk of misspelling exports
  • Better IDE support with autocompletion

Options

The "fileCommands" method takes the following options:

commandDirs

  • An array of directories where the routes are located relative to the build root folder.
  • Required

extensions

  • An array of file extensions for the route files. Files without matching extensions are ignored
  • Default: [".js", ".ts"]

ignorePatterns

  • An array of regexs which if matched against a filename or directory, lead it to being ignored/skipped over.
  • Default: [ /^[.|_].*/, /\.(?:test|spec)\.[jt]s$/, /__(?:test|spec)__/, /\.d\.ts$/ ]

logLevel

  • The verbosity level for the plugin, either debug or info
  • Default: "info"

Plugin Development (for Contributors only)

If you want to contribute, just check out this git project and run the following commands to get going:

# install dependencies
npm install

# build everything
npm run build

# prettify
npm run format

# eslint
npm run lint

# build and run tests
npm run test

# clean everything, should be like doing a fresh git checkout of the repo.
npm run clean

# publish the npm package
npm run publish

# run example cli
npx example-cli

Underneath the hood, we are using NX to manage the monorepo and shared scripts.