——

Extending the CLI

If you're familiar with Factor's filters system, then it's simple to add custom CLI commands for users of your app or extension.

Some use cases for this might be generating backup files, data downloads, creating deployment helpers, etc. Let's walk through how it's done.

Add A Custom Command

To add a custom CLI command, you just need to add a special filter using the cli-run- prefix on the filter ID.

The special custom CLI command filter is provided two special arguments:

program - is the arguments and values from Commander JS

inquirer - is an instance of the Inquirer CLI utility

The program argument is designed to pass along all the user's arguments and other information from the CLI.

The inquirer instance is useful to help create a dynamic interface for getting additional information from your user in an intuitive way. E.g. a file name or an option value.

Tip: Using inquirer instead of simple CLI options means that users won't have to do guesswork.

Example:

// index.js
import { addCallback } from "@factor/tools"

addCallback("cli-run-database-import", args => databaseImport(args))

export async function databaseImport({program, inquirer}){
  const questions = [
    {
      name: "file",
      message: "What is the path to the file for import?",
      type: "input"
    },
    {
      name: "collection",
      message: "Which collection should we import to?",
      type: "input"
    }]

    const answers = await inquirer.prompt(questions)

    const data = await require("fs-extra").readJson(resolve(process.cwd(), answers.file))

    // Import data...
  ]
}

Add Custom Setup (factor setup)

Many extensions require unique information from users. For example, API keys or user information for interfacing with an external service.

Setting this up can be a painful experience for end-users. Factor's setup utility is designed to solve this problem. It helps guide users and prevents the guesswork around what is needed and how exactly to set it up.

To add a custom command, all that is needed a filter. When a user selects your option, you will be provided the Commander program and Inquirer utility to work with.

Using those tools, gather the information you need from your user.

To write to the app's private or public config, use writeConfig as follows:

import { writeConfig } from "@factor/cli/setup"
// PRIVATE CONFIG: .env
await writeConfig(".env", {
  SOME_PRIVATE_SETTING: "VALUE"
})

// PUBLIC CONFIG: factor-config.json
await writeConfig("factor-config", {
  some_setting: "value"
})

Example

// server.js
import { writeConfig } from "@factor/cli/setup"
import { pushToFilter } from "@factor/tools"
pushToFilter("cli-add-setup", ({ privateConfig }) => {
  return {
    // Name of selection
    name: "DB Connection - Add/edit the connection string for MongoDB",
    // Value if selected
    value: "db",
    // What happens if user selects your setup option
    // provided both the CLI program (commander) and Inquirer utilities
    callback: async ({ program, inquirer }) => {
      const questions = [
        {
          name: "connection",
          message: "What's your MongoDB connection string? (mongodb://...)",
          type: "input",
          default: privateConfig.DB_CONNECTION
        }
      ]

      let { connection } = await inquirer.prompt(questions)

      await writeConfig(".env", { DB_CONNECTION: connection })
    }
  }
})