CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-oclif

A comprehensive CLI framework for creating command-line interfaces in Node.js and TypeScript

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

code-generation.mddocs/

Code Generation

Generate CLI components including commands and hooks using oclif's template system and code generators.

Capabilities

Generate Command

Adds a new command to an existing oclif CLI or plugin using predefined templates.

oclif generate command [NAME]

Arguments:

  • NAME (string, required) - Name of the command to create

Flags:

  • --commands-dir (string) - Directory to create the command file in
  • --force (boolean) - Overwrite existing command file if it exists

Usage Examples:

# Generate a simple command
oclif generate command hello

# Generate nested command
oclif generate command users:list

# Generate with custom directory
oclif generate command deploy --commands-dir=./src/commands

# Force overwrite existing command
oclif generate command existing-cmd --force

Generated Command Structure:

import { Args, Command, Flags } from '@oclif/core'

export default class Hello extends Command {
  static description = 'describe the command here'

  static examples = [
    '<%= config.bin %> <%= command.id %>',
  ]

  static flags = {
    // flag with a value (-n, --name=VALUE)
    name: Flags.string({char: 'n', description: 'name to print'}),
    // flag with no value (-f, --force)
    force: Flags.boolean({char: 'f'}),
  }

  static args = {
    file: Args.string({description: 'file to read'}),
  }

  async run(): Promise<void> {
    const {args, flags} = await this.parse(Hello)

    const name = flags.name ?? 'world'
    this.log(`hello ${name} from ./src/commands/hello/world.ts`)
    if (args.file && flags.force) {
      this.log(`you input --force and --file: ${args.file}`)
    }
  }
}

Generate Hook

Adds a new hook to an existing oclif CLI or plugin for extending functionality at specific lifecycle points.

oclif generate hook [NAME]

Arguments:

  • NAME (string, required) - Name of the hook to create (snake_case)

Flags:

  • --event (string) - Event to run hook on (default: "init")
  • --force (boolean) - Overwrite existing hook file if it exists

Usage Examples:

# Generate a basic init hook
oclif generate hook analytics

# Generate hook for specific event
oclif generate hook my_prerun_hook --event=prerun

# Force overwrite existing hook
oclif generate hook existing_hook --force

Generated Hook Structure:

import { Hook } from '@oclif/core'

const hook: Hook<'init'> = async function (opts) {
  // Hook implementation
  process.stdout.write(`example hook running ${opts.id}\n`)
}

export default hook

Generator Base Classes

oclif provides base generator classes for creating custom generators and extending the template system.

GeneratorCommand Class

Abstract base class for creating custom file generators using EJS templates.

/**
 * Base class for commands that generate files from templates
 */
abstract class GeneratorCommand<T extends typeof Command> extends Command {
  /** Get flag value or prompt user interactively */
  protected getFlagOrPrompt<K extends keyof FlagsOfPrompts<any>>(
    options: GetFlagOrPromptOptions<K>
  ): Promise<any>;

  /** Render EJS template to destination file */
  protected template(
    source: string,
    destination: string,
    data?: Record<string, any>
  ): Promise<void>;
}

interface GetFlagOrPromptOptions<K> {
  /** Flag name to check */
  flag: K;
  /** Prompt configuration */
  prompt: FlaggablePrompt;
  /** Default value if no flag or prompt response */
  default?: any;
}

interface FlaggablePrompt {
  /** Prompt message */
  message: string;
  /** Prompt type (input, select, confirm) */
  type: 'input' | 'select' | 'confirm';
  /** Choices for select prompts */
  choices?: Array<string | { name: string; value: any }>;
  /** Initial/default value */
  initial?: any;
}

Utility Functions

Helper functions for generator implementations and custom generators.

/**
 * Execute shell command with promise wrapper
 * @param command - Shell command to execute
 * @param opts - Execution options
 * @returns Promise resolving to command output
 */
function exec(command: string, opts?: ExecOptions): Promise<string>;

/**
 * Read and parse package.json file
 * @param location - Path to package.json
 * @returns Parsed package.json object
 */
function readPJSON(location: string): Promise<any>;

/**
 * Generate oclif flags from prompt definitions
 * @param flaggablePrompts - Array of prompt configurations
 * @returns oclif flag definitions object
 */
function makeFlags<T extends Record<string, FlaggablePrompt>>(
  flaggablePrompts: T
): FlagsOfPrompts<T>;

interface ExecOptions {
  cwd?: string;
  env?: Record<string, string>;
  shell?: boolean | string;
}

type FlagsOfPrompts<T extends Record<string, FlaggablePrompt>> = {
  [K in keyof T]: T[K]['type'] extends 'confirm' 
    ? BooleanFlag<boolean>
    : StringFlag<string | undefined>;
};

Template System

oclif uses EJS templates for code generation with built-in variables and helpers.

Template Variables

interface TemplateContext {
  /** Package configuration */
  config: {
    name: string;
    version: string;
    bin: string;
  };
  /** Command information */
  command: {
    id: string;
    name: string;
    className: string;
  };
  /** User input */
  answers: Record<string, any>;
  /** Utility functions */
  _: {
    camelCase: (str: string) => string;
    kebabCase: (str: string) => string;
    pascalCase: (str: string) => string;
    snakeCase: (str: string) => string;
  };
}

Template Locations

Templates are located in the oclif package and can be customized:

  • Command templates: templates/command/
  • Hook templates: templates/hook/
  • Project templates: templates/cli/

Custom Template Usage:

// In a custom generator command
await this.template(
  path.join(__dirname, '../templates/my-template.ejs'),
  path.join(this.config.root, 'generated-file.ts'),
  {
    className: 'MyClass',
    description: 'Custom generated class'
  }
);

Install with Tessl CLI

npx tessl i tessl/npm-oclif

docs

cli-management.md

code-generation.md

index.md

packaging.md

programmatic-api.md

upload-deployment.md

tile.json