Skip to content

Commit

Permalink
feat!: Refactored CLI, Typed Flags, Updated Docs & Build (v0.2.0) (#2)
Browse files Browse the repository at this point in the history
* refact!: Major refactor of the parser

* fix(lint): apply linter fixes

* feat!: complete CLI architecture redesign

BREAKING CHANGE: Restructured the entire CLI implementation with a modular approach

- Introduced namespaced architecture with Cli.Setup as main entry point
- Added strongly typed flag system with validation
- Implemented command tree-based parser
- Added usage/help text generation
- Introduced utility functions for type conversion

Changes include:
- Replaced monolithic Cli class with modular namespaces
- Added dedicated parser with tree-based command resolution
- Introduced TypedFlag system with built-in validation
- Added built-in help text generation
- Improved error handling and type safety
- Added caching for better performance
- Introduced string/number/boolean utilities

Closes #1

* feat: enhance CLI flag handling to support multiple values

* docs: update contributing guide file name

* test: add unit tests for utility functions

* test: add unit tests for UsageGenerator functionality

* test: update Utils.isValidBoolean tests to include numeric values

* test: add unit tests for Flag and Command classes

* refactor: clean up comments and improve code readability in Parser

* test: add unit tests for Parser functionality including Node, Tree, and Scope

* refactor: simplify isValid and convert methods in Flags namespace

* refactor: reorder imports for consistency and clarity in cli and usageGenerator files; update parser tests for improved import structure

* test: add unit tests for TypedFlag class in Flags module to validate initialization, input validation, conversion, and default values

* feat: introduce CliError class for improved error handling in CLI argument parsing

* feat: export CliError from cli module for enhanced error handling

* test: add comprehensive tests for Cli module covering setup, command and flag parsing, error handling, help generation, and default values

* refactor: improve test descriptions for clarity and consistency across CLI and Flags modules

* chore: add MIT License file to the repository

* feat: add benchmarking capabilities for Climonad CLI framework

* docs: update README and package.json for improved clarity and performance description

* chore: bump version to 0.2.0 in package.json

* fix: update package.json to correct module paths and exports configuration

* feat: expand keywords in package.json for better discoverability

* feat: enhance package.json with additional scripts and dependencies for improved testing and build processes

* fix: update devDependencies in package.json to latest versions for improved compatibility and performance

* fix: update Node.js engine version in package.json and package-lock.json to >=20.0.0
  • Loading branch information
supitsdu authored Dec 18, 2024
1 parent d1a2a6c commit 5dd876f
Show file tree
Hide file tree
Showing 21 changed files with 2,437 additions and 592 deletions.
File renamed without changes.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Eduardo Marques Santos

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
172 changes: 126 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

> ⚠️ This library is in **early development**. APIs may change without notice.
**A lightning-fast, lightweight library for building powerful command-line interfaces in Node.js.**
**A high-performance, low-overhead library for building modern command-line interfaces in Node.js.**

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Argument Parsing and Handling](#argument-parsing-and-handling)
- [Performance](#performance)
- [API Reference](#api-reference)
- [Contributing](#contributing)
Expand All @@ -26,88 +27,167 @@
### Define Your CLI

```javascript
import { Cli, Cmd, Bool, Str, Num } from "climonad"
import { Cli } from "climonad"

const cli = new Cli({
name: "my-app",
description: "A powerful CLI application",
// Global Commands:
commands: [
new Cmd({
Cli.cmd({
name: "init",
description: "Initialize the project",
alias: "i",
fn: () => console.log("Project initialization started..."),
}),
new Cmd({
Cli.cmd({
name: "build",
description: "Build the project",
alias: "b",
fn: (data) => {
console.log(`Building... (verbose: ${data.options.verbose}, output: ${data.options.output})`)
},
// Command Scoped Options:
options: [
Cli.str({
name: "output",
flag: "--out",
alias: "-o",
description: "Set output directory",
}),
],
}),
],
options: [
new Bool({ name: "verbose", alias: "v", description: "Enable verbose output" }),
new Str({ name: "output", alias: "o", description: "Specify output path" }),
],
// Global Options:
options: [Cli.bool({ name: "verboseOption", flag: "--verbose", description: "Enable verbose output" })],
})

cli.run(process.argv.slice(2))
```

## Performance
## Argument Parsing and Handling

> 💡 **Note**: These are preliminary metrics from an **early development version**. Climonad's API and performance are still evolving.
Climonad uses a declarative configuration approach to define and parse CLI arguments. Here's how it works:

`Climonad` is engineered for speed, and early benchmarks highlight its efficiency. These benchmarks were conducted using **Deno's built-in `bench` tool**, ensuring consistent and reliable results:
### Commands

| **Operation** | **Time (avg)** | **Ops/Second** |
| ----------------------- | -------------- | -------------- |
| CLI Initialization | ~309.4 ns | 3,232,000 |
| Basic Command Execution | ~244.9 ns | 4,083,000 |
| Command with Options | ~271.1 ns | 3,689,000 |
Commands represent distinct actions or functionalities. For example, "build" or "serve". You define commands using `Cli.cmd()` and assign them descriptions, aliases, and options. During runtime, Climonad identifies the invoked command based on the first positional argument:

```javascript
Cli.cmd({
name: "serve",
description: "Start the development server",
alias: "s",
})
```

Users can invoke this command using `serve` or its alias `s`:

```bash
my-app serve
my-app s
```

### Options

Options modify the behavior of commands. They are identified by flags (e.g., `--verbose`) or aliases (e.g., `-v`). Climonad supports different types of options:

- **Boolean Flags**: Toggle features on or off.
- **String Options**: Accept string values.
- **Number Options**: Accept numeric inputs.
- **Default Values**: Provide fallbacks when options are not specified.

Example:

```javascript
Cli.str({
name: "host",
flag: "--host",
description: "Specify the hostname",
default: "localhost",
})
Cli.num({
name: "port",
flag: "--port",
description: "Set the port number",
})
Cli.bool({
name: "verbose",
flag: "--verbose",
description: "Enable verbose logging",
})
```

Users can pass options as:

```bash
my-app serve --host localhost --port 8080 --verbose
```

## Testing Status 🧪
### Parsing Logic

- **Positional Arguments**: Climonad identifies commands based on their position. For example, in `my-app serve`, "serve" is a positional argument matched to a command.
- **Flag Arguments**: Options prefixed with `--` (or aliases like `-v`) are parsed and mapped to their respective definitions.
- **Default Values**: If a flag is not provided, Climonad falls back to the default value defined in its configuration.

Example:

```javascript
const result = cli.parse(["serve", "--host", "example.com", "--port", "3000"])
```

> 🛠️ If you'd like to contribute by expanding test coverage, check out our [Contributing section!](#contributing-)
Results in:

At this stage (v0.x.x), Climonad includes only a basic test to validate core functionality. Comprehensive tests for edge cases, integration scenarios, and performance are planned in upcoming releases.
```js
{
"commands": Set(1) { "serve" },
"options": Map(2) { "host" => "example.com", "port" => 3000 },
"generateHelp": [Function (anonymous)]
}
```

## API Reference
### Auto Help Generation

### `Cli`
Climonad provides built-in support for command-scoped help generation. Users can invoke the `-h` or `--help` flag to display detailed help information:

The main class for defining and running CLI applications.
- **Global Help**: When used without a command, it shows help for the entire CLI application.
- **Command-Scoped Help**: When used with a command, it displays help specific to that command.

#### Constructor
Example:

```typescript
new Cli({
name: string,
description: string,
commands?: Cmd[],
options?: Option[],
});
```bash
my-app --help
my-app serve --help
```

#### Methods
This feature is automatically enabled, requiring no additional configuration.

### Error Handling

Climonad provides robust error handling for invalid or unknown arguments. For example:

- If a required command or option is missing, it throws a `CliError`.
- If an invalid value is provided for a typed option (e.g., `--port not-a-number`), it raises an appropriate error.

## Performance

> 💡 **Note**: These are preliminary metrics from an **early development version**. Climonad's API and performance are still evolving.
- `run(args: string[])`: Parse and execute CLI commands.
These [`benchmarks`](test/bench.ts) were conducted using **Deno's built-in [`bench`](https://docs.deno.com/api/deno/~/Deno.bench) tool**, ensuring consistent and reliable results:

### `Cmd`
| **Operation** | **Time (avg)** | **Ops/Second** |
| ----------------------- | -------------- | -------------- |
| CLI Initialization | ~725.4 ns | 1,379,000 |
| Basic Command Execution | ~190.5 ns | 5,249,000 |
| Command with Options | ~654.5 ns | 1,528,000 |

Define commands with a name, description, and execution function.
### Algorithmic Complexity (Latest Update)

### Option Types
- **CLI Initialization**: O(n) where n is the total number of commands and options being registered
- **Command/Option Lookup**: O(1) using an optimized tree structure with path caching
- **Argument Parsing**: O(n) where n is the number of input arguments
- **Help Generation**: O(m) where m is the number of commands/options in the current scope
- **Space Complexity**: O(n) where n is the total number of registered commands and options, with a small additional overhead for the path cache which improves lookup performance.

- `Bool`: Boolean flags (`--verbose`).
- `Str`: String options (`--output path`).
- `Num`: Numeric options (`--buildNumber 42`).
Climonad is now highly efficient for both small scripts and large CLI applications with many commands and options.

## Contributing 🤝

[We love contributions!](/CONTRIBUTIONS_GUIDE.md) Here’s how you can help:
[We love contributions!](/CONTRIBUTING_GUIDE.md) Here’s how you can help:

1. 🐛 **Report Bugs**: Found a bug? [Open an issue](https://github.com/supitsdu/climonad/issues).
2. 💡 **Suggest Features**: Got an idea? Let us know by opening an issue.
Expand All @@ -118,4 +198,4 @@ Define commands with a name, description, and execution function.

## License

MIT License © 2024
Licensed under the [MIT License](LICENSE).
Loading

0 comments on commit 5dd876f

Please sign in to comment.