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

oclif-dynamic-commands

v1.1.0

Published

oclif plugin that loads commands dynamically from a directory.

Downloads

242

Readme

oclif-dynamic-commands

oclif plugin that loads commands dynamically on run.

The current folder's package.json is read to find the folders the dynamic commands can be found in.

Installation

  1. Install the library:
npm i oclif-dynamic-commands
  1. Add it to your oclif plugins in pacakge.json:
  "oclif": {
    "plugins": [
      "oclif-dynamic-commands"
      ...
    ],
    ...
  }

Writing Commands

Commands should be standard oclif commands, with one exception - command IDs are not defined by folder location, but manually and statically defined in the class itself:

import { Command } from '@oclif/core';

export default class Example extends Command {
  static id = 'example';
  static summary = 'An example command.';
  static description = 'A longer description of your example command.';
  static examples = [
    '$ your-cli-command example',
  ];

  async run(): Promise<void> {
    this.log('Example command has been run!');
  }
}

Configuration

In the folder that is to container your dynamic commands, ensure the package.json file has the following setting:

"oclif": {
  "dynamic-commands": {
    "folders": [
      "./lib/commands/**/*.ts",
      "./src/commands/**/*.ts"
    ]
  }
}

Folders will be explored in the order defined, and any new commands loaded will overwrite any existing commands with the same ID. In this way, you can allow for dynamic commands to override built-in commands, or allow for commands to be loaded from a common library, but still have project-specific commands overwrite them.

Entries in the folders array can use glob patterns from glob.

If you have commands separated into topics, you can set topic descriptions here as well:

"oclif": {
  "topics": {
    "your-dynamic-command-topic-name": {
      "description": "The description for your topic."
    }
  }
}

These topics and their descriptions will appear in the TOPICS section of your command help.

Caveats & Cautions

Typescript may be necessary!

If you are allowing users to write dynamic commands in Typescript, you will need to ensure your CLI is being run through Typescript, not running a pre-compiled Javascript binary! Otherwise, you will get syntax errors when Node attempts to parse a Typescript file.

One way to (relatively) easily do that is to add dev.sh and run.sh shell files to your binary folder that look like this:

#!/usr/bin/env bash

DIR="$(dirname "$(readlink -f "$0")")"

"$DIR/../node_modules/tsx/dist/cli.js" --tsconfig ./tsconfig.json -- $DIR/dev.js "$@"

This requires installing tsx in the dependencies of your CLI, which is a very quick Typescript interpreter, though it has a few limitations.

This script will run the dev.js Javascript file in your CLI's bin file, ensuring the tsconfig.json file from the current working directory is loaded. Which leads us to...

TsConfig differences between your CLI and your dynamic commands

With the above shell file, the tsconfig.json of the current working directory is used to run your CLI. This is not strictly necessary, but it can reduce issues with customised tsconfig values needed by your dynamic commands. Specifically, if the project that your dynamic commands live within requires a special paths setting, you must use the tsconfig.json from the project's folder to ensure those paths are loaded and set correctly. Otherwise, any includes from your dynamic commands that rely on those paths being set will fail.

This raises an interesting question: How do you have combine a paths setting from your project's tsconfig.json with one from your CLI? The short answer is that you cannot. So if you expect your dynamic commands to rely on custom paths, you cannot rely on them in your CLI.

You likely also want to both a) try to rely on as few custom TsConfig settings as you can and b) inform any developers of dynamic commands not to significantly modify their TsConfig settings or they could encounter unexpected failures when running the CLI.

Changelog

1.0.0 - Initial release. 1.0.1 - More-reliable method of determining if an exported value is a Command; adds license file. 1.1.0 - Commands in topics properly have their topic added to the command help, and "root commands" (commands with no topic separator) are no longer required to get your commands in topics to show up in the command help.