All files / src/cli cli.ts

0% Statements 0/28
0% Branches 0/10
0% Functions 0/4
0% Lines 0/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106                                                                                                                                                                                                                   
import { ProjectConfig } from "../config";
import { Datasource } from "../datasource";
 
import { commonPlugins, nonProjectPlugins, projectBasedPlugins } from "./plugins";
 
export interface ParsedOptions {
  _: string[];
  [key: string]: any;
}
 
export interface PluginHandlerOptions {
  rootDirectoryPath: string;
  projectConfig: ProjectConfig;
  datasource: Datasource;
  parsed: ParsedOptions;
}
 
export interface Plugin {
  command: string; // single word
  handler: (options: PluginHandlerOptions) => Promise<void | boolean>;
  examples: {
    command: string; // full command usage
    description: string;
  }[];
}
 
export interface RunnerOptions {
  rootDirectoryPath: string;
 
  // optional because Featurevisor CLI can be used without a project
  projectConfig?: ProjectConfig;
  datasource?: Datasource;
}
 
export async function runCLI(runnerOptions: RunnerOptions) {
  const yargs = require("yargs");
 
  let y = yargs(process.argv.slice(2)).usage("Usage: <command> [options]");
  const registeredSubcommands: string[] = [];
 
  const { rootDirectoryPath, projectConfig, datasource } = runnerOptions;
 
  function registerPlugin(plugin: Plugin) {
    const subcommand = plugin.command.split(" ")[0];
 
    if (registeredSubcommands.includes(subcommand)) {
      console.warn(`Plugin "${subcommand}" already registered. Skipping.`);
      return;
    }
 
    y = y.command({
      command: plugin.command,
      handler: async function (parsed: ParsedOptions) {
        try {
          const result = await plugin.handler({
            rootDirectoryPath,
            projectConfig,
            datasource,
            parsed,
          } as PluginHandlerOptions);
 
          if (result === false) {
            process.exit(1);
          }
        } catch (error) {
          console.error(error);
          process.exit(1);
        }
      },
    });
 
    for (const example of plugin.examples) {
      y = y.example(`$0 ${example.command}`, example.description);
    }
 
    registeredSubcommands.push(subcommand);
  }
 
  // non project-based plugins
  if (!projectConfig) {
    for (const plugin of nonProjectPlugins) {
      registerPlugin(plugin);
    }
  }
 
  // project-based plugins
  if (projectConfig) {
    for (const plugin of [...projectBasedPlugins, ...(projectConfig.plugins || [])]) {
      registerPlugin(plugin);
    }
  }
 
  // common plugins
  for (const plugin of commonPlugins) {
    registerPlugin(plugin);
  }
 
  // show help if no command is provided
  y.command({
    command: "*",
    handler() {
      y.showHelp();
    },
  }).argv;
}