Clide-JS
is a Command Line Interface (CLI) framework for node designed to
build powerful and flexible command-line applications with ease. It leverages a
modular approach, allowing developers to create commands, use hooks for
lifecycle management, and extend functionality with plugins.
npm install clide-js
# or
yarn add clide-js
1. Import and call the run
function
// src/cli.ts
import { run } from 'clide-js';
// Use argv (minus the binary name) and the default commands directory.
run();
// Or pass in your own + some options
run({
command: 'deploy dev --watch',
commandsDir: path.join(__dirname, 'modules'),
initialData: { ... }
plugins: [help()]
})
2. Use the command
function to define your commands in separate files:
// src/commands/hello.ts
import { command } from 'clide-js';
export default command({
description: 'Say hello!',
options: {
name: {
description: 'The name to greet',
type: 'string',
alias: ['n'],
default: 'World',
},
},
handler: async ({ context, end, next, options }) => {
// Use the options getter to dynamically retrieve option values.
const name = options.name({
prompt: 'Enter your name',
});
const message = `Hello, ${name}!`;
// Use the client to log messages or show arbitrary prompts
context.client.log(message);
// Send some data to the next command
next(message);
// Or end the command and return some data
end(message);
},
});
3. (Optional) Create plugins to extend the framework:
import { Plugin } from 'clide-js';
export function logger(): Plugin {
return {
name: 'logger',
version: '1.0.0',
description: 'Logs the result of each execution step.',
init: ({ client, commandString, hooks }) => {
client.log('🪵 Received command:', commandString);
hooks.on('beforeNext', ({ data, state }) => {
client.log('🪵 Next:', {
commandName: state.command.commandName,
commandTokens: state.command.commandTokens,
commandPath: state.command.commandPath,
params: state.params,
data: state.data,
});
});
hooks.on('beforeEnd', ({ data, state }) => {
log('🪵 End:', {
commandName: state.command.commandName,
commandTokens: state.command.commandTokens,
commandPath: state.command.commandPath,
params: state.params,
data: state.data,
});
});
// return true to indicate successful initialization
return true;
},
};
}
Clide-JS is ideal for developers looking to create efficient, maintainable CLI applications with minimal fuss. It offers the right balance of functionality and ease-of-use, making it a practical choice for both simple scripts and more elaborate command-line tools.
Clide-JS is designed to be straightforward to run. The primary entry point is
the run
function,
which orchestrates the command execution flow. It parses and executes commands
based on your configuration, handles plugins, and utilizes hooks for lifecycle
management.
The run
function
takes an optional configuration
object
allowing you to specify commands, plugins, and hooks. This level of
customization makes it adaptable to various CLI application requirements.
For detailed API information on the
run
function,
please refer to the Typedoc
reference.
In Clide-JS, commands are the building blocks of your CLI application. Each command can have its description, options, and a handler function where the command's logic resides. Clide-JS allows for dynamic command resolution, meaning your commands can be organized hierarchically, with support for nested and parameterized commands.
To create a command, use the
command
factory
function. This function takes an object with your command's metadata, options,
and the handler function. The handler function, which is where the main logic of
your command lives, receives a
State
object. This
object provides access to parsed options, command parameters, and the ability to
control the command execution flow.
For a comprehensive guide on creating commands, including handling options and parameters, see the Typedoc reference.
Plugins in Clide-JS offer a way to extend and customize the framework's
functionality. A plugin is an object that includes metadata (name, version,
description) and an
init
function. This function is called during the CLI application's initialization
phase and receives the application's
Context
. The
Context
provides
access to hooks, commands, and other critical framework components.
You can create plugins to add new features, integrate with external services,
modify existing behavior, or inject middleware for advanced use cases. The
init
function should return a boolean indicating whether the initialization was
successful.
For more information on developing plugins, including accessing and modifying the application context, refer to the Typedoc reference.
--help
/-h
option and manages printing help messages when the option is
present or a
UsageError
occurs. Included in the core package.If you don't explicitly provide a commands directory when calling the
run
function, the
framework automatically attempts to locate the commands directory in two ways:
run
function.
This is helpful for scenarios where your CLI script lives in a specific
directory within your project (e.g., "cli/bin.js") and the commands are kept
in a sibling directory called "cli/commands".1. Parse Command String:
2. Find Command File:
CommandModule
object.3. Handle Non-existent Files:
[param].ts
).4. Handle Parameterized Commands:
[param].ts
or [...param].ts
to
capture arguments.5. Prepare Resolved Command:
Once a command file is found:
resolveNext
function is added if the command isn't the last one in the
string for further resolution of subcommands.isMiddleware
is false
), its
handler is replaced with a pass-through function.1. Basic Command:
mycli list
The framework searches for list.js
in the commands directory. If found, it
imports the module and executes its handler.
2. Pass-through Command:
mycli settings ...
The framework identifies settings
as a directory, treats it as a pass-through
command, and expects further command resolution within the settings
directory.
4. Subcommand:
mycli users create
users.js
or a users
directory is first resolved, then create
is
identified as a subcommand.create.js
in the users
directory.3. Parameterized Command:
mycli deploy prod
deploy
, The framework searches for prod.ts
in the deploy
directory.[environment].ts
.environment
is set to prod
in the
State.params
.This flexible approach allows for intuitive command structures and efficient execution, making it ideal for building versatile CLI applications.
Clide-JS introduces a dynamic and user-centric approach to handling command
options, distinguishing it from many other CLI frameworks. Instead of validating
options before execution, Clide-JS's
OptionsGetter
allows command handlers to address missing or invalid options dynamically,
enhancing the user experience and offering more flexibility:
getter
function that
dynamically retrieves its value. Getters can prompt users for missing values,
validate input, and provide default values if needed.When creating commands, the
OptionsGetter
provides a straightforward and intuitive interface for accessing and handling
options.
// Example usage in a command
options: {
n: {
type: 'string',
alias: ['name'],
},
a: {
type: 'string',
alias: ['alt-name'],
}
},
handler: async ({ options, next }) => {
// Getter functions
const name = await options.n();
const altName = await options.a();
// Alias getter functions
const name = await options.name();
const altName = await options.altName();
// Get function
const { name, altName } = options.get(['name', 'alt-name']);
// Direct values access
const { name, altName } = options.values;
},
Visit the examples directory for some basic setups.
Clide-JS uses Typedoc to autogenerate detailed references for each major component of the framework. See the Typedoc reference for a full breakdown of Clide-JS's APIs.
Clide-JS is a new framework still under development. Contributions are welcome! You can get a brief overview of the code base in /notes/source-code.md. If you're unsure where to start, or if a feature would be welcomed, open an issue and start a conversation.