Decaf's Utils Module
A comprehensive TypeScript utility library providing robust tools for command-line interfaces, input handling, output management, file system operations, HTTP requests, text processing, and more. This module serves as a foundation for building powerful CLI applications with standardized input parsing, flexible output formatting, and a rich set of utility functions.
Documentation available here
Description
The Decaf Utils module is a comprehensive TypeScript utility library designed to standardize APIs across repositories and provide a robust foundation for building command-line interface (CLI) applications. The library is organized into several key components:
CLI Module
The CLI module provides a structured framework for creating command-line applications:
- Abstract
Command
class for implementing custom CLI commands with standardized input handling, logging, and execution flow - Command option handling with support for common flags like verbose, version, help, etc.
- Standardized command execution flow with proper error handling
Input Module
The Input module offers tools for handling user input and command-line arguments:
UserInput
class for creating interactive prompts with various input types (text, number, confirmation, etc.)- Support for input validation, formatting, and default values
- Command-line argument parsing with type checking and validation
- Methods for repeatedly asking for input until valid responses are received
Utils Module
The Utils module contains a wide range of utility functions:
- File System Operations: Reading, writing, copying, and deleting files and directories
- Package Management: Retrieving package information, managing dependencies, and version handling
- HTTP Utilities: Simple client for downloading files from URLs
- Text Processing: String interpolation, case conversion (camelCase, snake_case, etc.), and regular expression utilities
- Environment Handling: Working with environment variables and configuration
Writers Module
The Writers module provides different strategies for handling command output:
OutputWriter
interface defining a standard contract for output handlingStandardOutputWriter
for handling standard command-line output with proper loggingRegexpOutputWriter
for processing output with regular expressions and pattern matching
Output Module
The Output module offers utilities for formatting and displaying output:
- Common output formatting functions
- Banner display capabilities
This library serves as a light version of the Decaf CLI tool, providing all the essential utilities needed for building robust command-line applications with consistent input handling, output formatting, and error management.
How to Use
Examples
CLI Module
Creating a Custom Command
The Command class provides a foundation for creating custom CLI commands with standardized input handling and execution flow.
import { Command, CommandOptions } from '@decaf-ts/utils';
// Define input options interface
interface MyCommandOptions {
filename: string;
dryRun: boolean;
}
// Create a custom command class
class MyCommand extends Command<MyCommandOptions, string> {
constructor() {
// Define command options with their configurations
const options: CommandOptions<MyCommandOptions> = {
filename: {
type: 'string',
short: 'f',
default: 'output.txt'
},
dryRun: {
type: 'boolean',
short: 'd',
default: false
}
};
super('my-command', options);
}
// Override the help method to provide custom help information
protected help(): void {
this.log.info(`
Usage: my-command [options]
Options:
-f, --filename Specify output filename (default: output.txt)
-d, --dryRun Run without making changes (default: false)
-h, --help Show help information
-v, --version Show version information
`);
}
// Implement the run method to define command behavior
protected async run(answers: { filename: string; dryRun: boolean }): Promise<string> {
this.log.info(`Running command with filename: ${answers.filename}, dryRun: ${answers.dryRun}`);
// Command implementation here
return 'Command executed successfully';
}
}
// Execute the command
async function main() {
const command = new MyCommand();
const result = await command.execute();
console.log(result);
}
main().catch(console.error);
Input Module
Creating Interactive Prompts
The UserInput class allows you to create interactive prompts for collecting user input.
import { UserInput } from '@decaf-ts/utils';
async function collectUserInfo() {
// Create a text input for name
const nameInput = new UserInput('name')
.setMessage('What is your name?')
.setInitial('User');
// Create a number input for age with validation
const ageInput = new UserInput('age')
.setType('number')
.setMessage('How old are you?')
.setMin(0)
.setMax(120)
.setValidate(value => {
if (value < 18) return 'You must be at least 18 years old';
return true;
});
// Create a confirmation input
const confirmInput = new UserInput('confirm')
.setType('confirm')
.setMessage('Is this information correct?')
.setInitial(true);
// Ask for all inputs and get the answers
const answers = await UserInput.ask([nameInput, ageInput, confirmInput]);
console.log(`Hello ${answers.name}, you are ${answers.age} years old.`);
console.log(`Information confirmed: ${answers.confirm ? 'Yes' : 'No'}`);
return answers;
}
collectUserInfo().catch(console.error);
Using Convenience Methods for Input
UserInput provides static convenience methods for common input scenarios.
import { UserInput } from '@decaf-ts/utils';
async function quickInputExample() {
// Ask for text input
const name = await UserInput.askText('name', 'What is your name?', undefined, 'User');
// Ask for number input
const age = await UserInput.askNumber('age', 'How old are you?', 0, 120);
// Ask for confirmation
const confirm = await UserInput.askConfirmation('confirm', 'Is this information correct?', true);
// Ask for text with validation and retry until valid
const email = await UserInput.insistForText(
'email',
'What is your email address?',
(value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
undefined,
undefined,
false,
3 // Maximum 3 attempts
);
console.log(`Name: ${name}, Age: ${age}, Email: ${email}, Confirmed: ${confirm}`);
}
quickInputExample().catch(console.error);
Parsing Command-Line Arguments
import { UserInput, ParseArgsOptionsConfig } from '@decaf-ts/utils';
// Define command-line options
const options: ParseArgsOptionsConfig = {
verbose: {
type: 'boolean',
short: 'V',
default: false
},
output: {
type: 'string',
short: 'o',
default: 'output.txt'
},
count: {
type: 'string',
short: 'c',
default: '10'
}
};
// Parse command-line arguments
const args = UserInput.parseArgs(options);
console.log('Parsed arguments:', args.values);
console.log('Positional arguments:', args.positionals);
Utils Module
File System Operations
import {
readFile,
writeFile,
patchFile,
getAllFiles,
copyFile,
renameFile,
deletePath
} from '@decaf-ts/utils';
// Read a file
const content = readFile('./config.json');
console.log('File content:', content);
// Write to a file
writeFile('./output.txt', 'Hello, world!');
// Patch a file with replacements
patchFile('./template.txt', {
'{{name}}': 'John Doe',
'{{date}}': new Date().toISOString()
});
// Get all files in a directory
const files = getAllFiles('./src', (file) => file.endsWith('.ts'));
console.log('TypeScript files:', files);
// Copy a file
copyFile('./source.txt', './destination.txt');
// Rename a file
renameFile('./old-name.txt', './new-name.txt');
// Delete a file or directory
deletePath('./temp');
Package Management
import {
getPackage,
getPackageVersion,
setPackageAttribute,
getDependencies,
installDependencies
} from '@decaf-ts/utils';
// Get package information
const pkg = getPackage();
console.log('Package:', pkg);
// Get package version
const version = getPackageVersion();
console.log('Version:', version);
// Set a package attribute
setPackageAttribute('version', '1.0.1');
// Get dependencies
async function manageDependencies() {
const deps = await getDependencies();
console.log('Production dependencies:', deps.prod);
console.log('Development dependencies:', deps.dev);
console.log('Peer dependencies:', deps.peer);
// Install dependencies
await installDependencies({
prod: ['lodash', 'axios'],
dev: ['typescript', 'jest']
});
}
manageDependencies().catch(console.error);
HTTP Utilities
import { HttpClient } from '@decaf-ts/utils';
async function downloadExample() {
try {
// Download a file from a URL
const content = await HttpClient.downloadFile('https://example.com/api/data.json');
console.log('Downloaded content:', content);
// Parse JSON content
const data = JSON.parse(content);
console.log('Parsed data:', data);
return data;
} catch (error) {
console.error('Download failed:', error);
throw error;
}
}
downloadExample().catch(console.error);
Text Processing
import {
padEnd,
patchPlaceholders,
patchString,
toCamelCase,
toSnakeCase,
toKebabCase,
toPascalCase,
toENVFormat
} from '@decaf-ts/utils';
// Pad a string
const padded = padEnd('Hello', 10, '-');
console.log(padded); // 'Hello-----'
// Replace placeholders
const template = 'Hello, ${name}! Today is ${day}.';
const filled = patchPlaceholders(template, {
name: 'Alice',
day: 'Monday'
});
console.log(filled); // 'Hello, Alice! Today is Monday.'
// Replace strings
const patched = patchString('Hello, world!', {
'world': 'universe'
});
console.log(patched); // 'Hello, universe!'
// Case conversion
const text = 'hello world';
console.log(toCamelCase(text)); // 'helloWorld'
console.log(toSnakeCase(text)); // 'hello_world'
console.log(toKebabCase(text)); // 'hello-world'
console.log(toPascalCase(text)); // 'HelloWorld'
console.log(toENVFormat(text)); // 'HELLO_WORLD'
Writers Module
Using StandardOutputWriter
import { StandardOutputWriter } from '@decaf-ts/utils';
// Create a promise executor
const executor = {
resolve: (value: string) => console.log(`Command succeeded with: ${value}`),
reject: (error: Error) => console.error(`Command failed with: ${error.message}`)
};
// Create a standard output writer
const writer = new StandardOutputWriter('ls -la', executor);
// Handle command output
writer.data('File list output...');
writer.data('file1.txt');
writer.data('file2.txt');
// Handle command completion
writer.exit(0, ['Command executed successfully']);
Using RegexpOutputWriter
import { RegexpOutputWriter } from '@decaf-ts/utils';
// Create a promise executor
const executor = {
resolve: (value: string) => console.log(`Found version: ${value}`),
reject: (error: Error) => console.error(`Error: ${error.message}`)
};
// Create a regexp output writer that matches version numbers
const writer = new RegexpOutputWriter('node --version', executor, /v(\d+\.\d+\.\d+)/);
// Process output that contains a version number
writer.data('v14.17.0'); // This will automatically resolve with "v14.17.0"
// Process error output
writer.error('Command not found: node'); // This will be logged as an error
Related
Social
Languages
Getting help
If you have bug reports, questions or suggestions please create a new issue.
Contributing
I am grateful for any contributions made to this project. Please read this to get started.
Supporting
The first and easiest way you can support it is by Contributing. Even just finding a typo in the documentation is important.
Financial support is always welcome and helps keep both me and the project alive and healthy.
So if you can, if this project in any way. either by learning something or simply by helping you save precious time, please consider donating.
License
This project is released under the MIT License.
By developers, for developers...