Launch your command line tool with ease by handling configuration discovery, local module resolution, and process management.
npx @tessl/cli install tessl/npm-liftoff@5.0.0Liftoff is a Node.js library that simplifies the creation and management of command-line tools by automatically handling common tasks like finding and loading configuration files, resolving local module paths, managing v8 flags, and supporting various file extensions through custom loaders.
npm install liftoffconst Liftoff = require('liftoff');For ES modules:
import Liftoff from 'liftoff';const Liftoff = require('liftoff');
// Create a new CLI launcher
const MyApp = new Liftoff({
name: 'myapp',
extensions: {
'.js': null,
'.json': null,
'.coffee': 'coffee-script/register',
},
v8flags: ['--harmony']
});
// Launch the application
MyApp.prepare({}, function(env) {
MyApp.execute(env, function(env, argv) {
// Your CLI application logic here
console.log('Current working directory:', env.cwd);
console.log('Config file found at:', env.configPath);
console.log('Local module path:', env.modulePath);
});
});Liftoff is built around several key components:
Manages the complete lifecycle of CLI tool execution from environment preparation to final execution with automatic configuration discovery and process management.
/**
* Creates a new Liftoff instance for launching CLI applications
* @param opts - Configuration options for the CLI launcher
* @throws {Error} If name is not provided and any of processTitle, moduleName, or configName are missing
*/
function Liftoff(opts: LiftoffOptions): Liftoff;
interface LiftoffOptions {
/** Name of the CLI tool (sets processTitle, moduleName, configName if not specified) */
name?: string;
/** Title to set for the process (required if name not provided) */
processTitle?: string;
/** Name of the local module to find and require (required if name not provided) */
moduleName?: string;
/** Base name of configuration files to search for (required if name not provided) */
configName?: string;
/** File extensions and their loaders */
extensions?: { [ext: string]: string | null };
/** V8 flags to apply during respawn */
v8flags?: string[] | ((callback: (err: Error | null, flags?: string[]) => void) => void);
/** Function to handle shell completions */
completions?: (type: string) => void;
/** Array of configuration file search specifications */
configFiles?: ConfigFileSpec[];
/** Additional search paths for configuration discovery */
searchPaths?: string[];
}
interface ConfigFileSpec {
/** Base name of the config file */
name?: string;
/** Path to search in */
path: string;
/** File extensions to try */
extensions?: string[] | { [ext: string]: string | null };
/** Base directory for relative paths */
cwd?: string;
/** Whether to search up the directory tree */
findUp?: boolean;
}Builds execution environment by discovering configuration files, resolving module paths, and preparing the runtime context with all necessary metadata.
/**
* Builds the execution environment with configuration and module resolution
* @param opts - Options for environment building
* @returns Environment object with discovered paths and configuration
*/
buildEnvironment(opts?: EnvironmentOptions): Environment;
interface EnvironmentOptions {
/** Current working directory override */
cwd?: string;
/** Explicit path to configuration file */
configPath?: string;
/** Modules to preload before execution */
preload?: string | string[];
/** Completion data for shell completions */
completion?: any;
}
interface Environment {
/** Current working directory */
cwd: string;
/** Array of modules that will be preloaded */
preload: string[];
/** Regex or array of config file names searched */
configNameSearch: RegExp | string[];
/** Full path to found configuration file */
configPath: string | null;
/** Directory containing the configuration file */
configBase: string | null;
/** Full path to the local module */
modulePath: string | null;
/** Contents of the local module's package.json */
modulePackage: object;
/** Array of found configuration file paths */
configFiles: (string | null)[];
/** Array of loaded configuration objects */
config: object[];
}Handles discovery and loading of configuration files with support for multiple formats, inheritance through extends, and flexible search patterns.
/**
* Configuration file inheritance and loading system
* Supports extends property for config inheritance
* Handles circular reference detection
* Loads custom extensions through registered loaders
*/
interface ConfigurationSystem {
/** Extend configurations support circular detection */
extends?: string | ConfigFileSpec;
/** Override config path discovery */
[configName: string]?: string;
/** Additional modules to preload */
preload?: string | string[];
}EventEmitter-based system providing lifecycle hooks for module preloading, loader registration, and process respawning with detailed status information.
/**
* Liftoff extends EventEmitter and emits lifecycle events
*/
interface LiftoffEvents {
/** Emitted before attempting to preload a module */
'preload:before': (moduleName: string) => void;
/** Emitted when a module is successfully preloaded */
'preload:success': (moduleName: string, module: any) => void;
/** Emitted when module preloading fails */
'preload:failure': (moduleName: string, error: Error) => void;
/** Emitted when a file extension loader is successfully registered */
'loader:success': (loaderName: string, module: any) => void;
/** Emitted when a file extension loader fails to load */
'loader:failure': (loaderName: string, error: Error) => void;
/** Emitted when process is respawned for v8 flags */
'respawn': (flags: string[], childProcess: object) => void;
}/**
* Main Liftoff class extending EventEmitter
*/
class Liftoff extends EventEmitter {
constructor(opts: LiftoffOptions);
/** Build execution environment */
buildEnvironment(opts?: EnvironmentOptions): Environment;
/** Prepare environment and invoke callback */
prepare(opts: EnvironmentOptions, callback: (env: Environment) => void): void;
/** Execute application with environment */
execute(env: Environment, callback: (env: Environment, argv: string[]) => void): void;
execute(env: Environment, forcedFlags: string[], callback: (env: Environment, argv: string[]) => void): void;
/** Require a module from local working directory */
requireLocal(moduleName: string, basedir: string): any;
/** Handle v8flags resolution */
handleFlags(callback: (err: Error | null, flags?: string[]) => void): void;
}