Rails-inspired generator system that provides scaffolding for your apps
Options and arguments definition system with parsing, validation, and help generation for creating command-line tools with Yeoman generators.
Define command line options with type validation, defaults, and help text.
/**
* Adds an option to the set of generator expected options
* By default, generators get all the CLI options parsed by nopt as this.options hash
* @param name - Option name or option specification object
* @param config - Option configuration
* @returns This generator for chaining
*/
option(name: string | CliOptionSpec | CliOptionSpec[], config?: Partial<Omit<CliOptionSpec, 'name'>>): this;Usage Examples:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
// Basic boolean option
this.option('skip-install', {
type: Boolean,
description: 'Skip npm install',
default: false
});
// String option with alias
this.option('project-name', {
type: String,
alias: 'n',
description: 'Name of the project',
default: 'my-project'
});
// Number option
this.option('port', {
type: Number,
description: 'Server port number',
default: 3000
});
// Hidden option (not shown in help)
this.option('internal-flag', {
type: Boolean,
hide: true,
description: 'Internal use only'
});
// Option with storage
this.option('author', {
type: String,
description: 'Author name',
storage: this.config // Store in generator config
});
}
initializing() {
// Access options
if (this.options.skipInstall) {
this.log('Skipping npm install...');
}
this.log(`Project name: ${this.options.projectName}`);
this.log(`Port: ${this.options.port}`);
}
}Define positional command line arguments with type validation and requirements.
/**
* Adds an argument to the class and creates an attribute getter for it
* Arguments are different from options - they are retrieved based on their position
* @param name - Argument name
* @param config - Argument configuration
* @returns This generator for chaining
*/
argument(name: string, config?: Partial<ArgumentSpec>): this;Usage Examples:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
// Required string argument
this.argument('appname', {
type: String,
description: 'Name of the application',
required: true
});
// Optional argument with default
this.argument('template', {
type: String,
description: 'Template to use',
required: false,
default: 'basic'
});
// Array argument (captures remaining arguments)
this.argument('features', {
type: Array,
description: 'Features to include',
required: false,
default: []
});
}
initializing() {
// Access arguments
this.log(`App name: ${this.options.appname}`);
this.log(`Template: ${this.options.template}`);
this.log(`Features: ${this.options.features.join(', ')}`);
// Also available as this.args array
this.log(`Raw arguments: ${this.args.join(' ')}`);
}
}Automatic help text generation with usage information and option/argument documentation.
/**
* Generate help message for the generator
* @returns Complete help message with usage, options, and arguments
*/
help(): string;
/**
* Generate usage information for this generator
* @returns Usage line showing proper command syntax
*/
usage(): string;
/**
* Set custom description to append on help output
* @param description - Description text
* @returns This generator for chaining
*/
desc(description: string): this;
/**
* Get help text for arguments
* @returns Formatted table of arguments with descriptions
*/
argumentsHelp(): string;
/**
* Get help text for options
* @returns Formatted table of options with descriptions
*/
optionsHelp(): string;Usage Examples:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
// Set generator description
this.desc('Generate a new Node.js project with customizable features');
// Define options and arguments
this.argument('name', {
type: String,
description: 'Project name',
required: true
});
this.option('typescript', {
type: Boolean,
alias: 't',
description: 'Use TypeScript',
default: false
});
this.option('package-manager', {
type: String,
alias: 'pm',
description: 'Package manager to use',
default: 'npm'
});
}
// Users can run: yo myapp --help
// This will automatically generate help text like:
//
// Usage:
// yo myapp <name> [options]
//
// Generate a new Node.js project with customizable features
//
// Options:
// -t, --typescript Use TypeScript Default: false
// --pm, --package-manager Package manager to use Default: npm
// -h, --help Print the generator's options and usage
//
// Arguments:
// name Project name Type: String Required: true
}Automatic parsing and validation of command line options and arguments.
/**
* Parse command line options and arguments
* Usually called automatically, but can be called manually
*/
parseOptions(): void;
/**
* Check that all required arguments are present
* Throws error if required arguments are missing
*/
checkRequiredArgs(): void;Usage Example:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
this.argument('name', { type: String, required: true });
this.option('force', { type: Boolean, default: false });
// Parsing is automatic, but you can force it
if (this.features.skipParseOptions) {
this.parseOptions();
}
}
initializing() {
// Arguments and options are parsed and available
this.log(`Creating project: ${this.options.name}`);
if (this.options.force) {
this.log('Force mode enabled');
}
}
}Standard options available in all generators.
// Built-in options (automatically available)
interface BuiltInOptions {
help: boolean; // -h, --help: Print generator help
skipCache: boolean; // --skip-cache: Do not remember prompt answers
skipInstall: boolean; // --skip-install: Do not automatically install dependencies
forceInstall: boolean; // --force-install: Fail on install dependencies error
askAnswered: boolean; // --ask-answered: Show prompts for already configured options
}Usage Example:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
// Built-in options are always available
if (this.options.help) {
// Help will be shown automatically, this won't run
return;
}
}
async prompting() {
// skipCache affects prompt behavior
if (!this.options.skipCache) {
this.log('Using cached answers...');
}
this.answers = await this.prompt([...]);
}
install() {
// skipInstall affects install behavior
if (!this.options.skipInstall) {
this.spawnCommand('npm', ['install']);
}
}
}Complex option configurations with custom types and validation.
Usage Examples:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
// Custom type converter
this.option('features', {
type: (val) => val.split(','),
description: 'Comma-separated list of features',
default: []
});
// Multiple option objects at once
this.option([
{
name: 'verbose',
type: Boolean,
alias: 'v',
description: 'Verbose output',
default: false
},
{
name: 'config-file',
type: String,
description: 'Path to config file',
storage: this.config
}
]);
// Required option
this.option('api-key', {
type: String,
required: true,
description: 'API key for service'
});
}
initializing() {
// Validate custom requirements
if (this.options.features.includes('database') && !this.options.dbUrl) {
throw new Error('Database feature requires --db-url option');
}
}
}Automatic persistence of option values to configuration storage.
Usage Example:
export default class MyGenerator extends Generator {
constructor(args, opts) {
super(args, opts);
// Options with storage are automatically persisted
this.option('author-name', {
type: String,
description: 'Author name',
storage: this.config, // Store in .yo-rc.json
default: 'Anonymous'
});
this.option('git-email', {
type: String,
description: 'Git email',
storage: 'config', // Store in this.config by name
default: async () => await this.git.email()
});
}
configuring() {
// Stored options are automatically available in config
const authorName = this.config.get('authorName');
const gitEmail = this.config.get('gitEmail');
this.log(`Config author: ${authorName}`);
this.log(`Config email: ${gitEmail}`);
}
}interface CliOptionSpec {
name: string;
type: typeof Boolean | typeof String | typeof Number | ((opt: string) => any);
required?: boolean;
alias?: string;
default?: any;
description?: string;
hide?: boolean;
storage?: string | Storage;
}
interface ArgumentSpec {
name: string;
description?: string;
required?: boolean;
optional?: boolean;
type: typeof String | typeof Number | typeof Array | typeof Object;
default?: any;
}Install with Tessl CLI
npx tessl i tessl/npm-yeoman-generator