Skip to content

Commit

Permalink
doc(book): extend the docs about cli and generators
Browse files Browse the repository at this point in the history
Extend the docs around these sections and create an example in
`mabo-cli` which auto-generates the doc pages for the CLI subcommands.
  • Loading branch information
dnaka91 committed Jan 19, 2024
1 parent 443c32c commit a1474d9
Show file tree
Hide file tree
Showing 16 changed files with 307 additions and 10 deletions.
2 changes: 1 addition & 1 deletion book/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default defineConfig({
text: "Command Line Interface",
link: "/reference/cli/",
items: [
{ text: "mabo lint", link: "/reference/cli/lint" },
{ text: "mabo init", link: "/reference/cli/init" },
{ text: "mabo check", link: "/reference/cli/check" },
{ text: "mabo fmt", link: "/reference/cli/fmt" },
{ text: "mabo doc", link: "/reference/cli/doc" },
Expand Down
4 changes: 4 additions & 0 deletions book/src/guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Currently it can only be installed from source, using Cargo:
cargo install --git https://github.com/dnaka91/mabo.git mabo-cli
```

::: tip
If the installation fails, it can be that your Rust installation is too old. Please ensure you have the latest stable release installed. The easiest way to manage Rust is through [Rustup](https://rustup.rs/).
:::

## Rust

For Rust projects, two crates are needed to work with Mabo schemas and data. One is the `mabo` crate for runtime support, which contains all components that are used by the generated code.
Expand Down
27 changes: 27 additions & 0 deletions book/src/reference/cli/check.md
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
---
editLink: false
lastUpdated: false
---

# mabo check

- Aliases: `c`

Check that a project or set of files are valid schemas.

This involves first checking each schema individually to be parseable, then run various lints over it and finally resolve any external schema types. In case any of the steps fail an error will be returned.

## Arguments

### `FILES`

Loose list of glob patterns for files that should be checked instead of a project.

Using this will disable the loading of a project and instead locate the files from the glob patterns, then treat them as one single set. The files will be treated as a single project but the `Mabo.toml` file is fully ignored.

## Options

### `--project-dir`

Alternative location of the project directory containing a `Mabo.toml` file.

By default, the current directory is assumed to be the project directory. This is the root from where the command operates. Therefore, using it has the same effect as moving to the project directory and executing the command without it.
25 changes: 25 additions & 0 deletions book/src/reference/cli/doc.md
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
---
editLink: false
lastUpdated: false
---

# mabo doc

- Aliases: `d`, `document`

Generate documentation for a project.

## Arguments

### `OUT_DIR`

Directory where the documentation files are written to.

Note that this directory will be overwritten without confirmation. Any existing files will be replaced, but the directory is not fully cleared beforehand. That means any unrelated files not having the same name as any documentation file, will remain.

## Options

### `--project-dir`

Alternative location of the project directory containing a `Mabo.toml` file.

By default, the current directory is assumed to be the project directory. This is the root from where the command operates. Therefore, using it has the same effect as moving to the project directory and executing the command without it.
25 changes: 25 additions & 0 deletions book/src/reference/cli/fmt.md
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
---
editLink: false
lastUpdated: false
---

# mabo fmt

- Aliases: `f`, `format`

Format a project or set of files.

## Arguments

### `FILES`

Loose list of glob patterns for files that should be formatted instead of a project.

Using this will disable the loading of a project and instead locate the files from the glob patterns, then treat them as one single set. The files will be treated as a single project but the `Mabo.toml` file is fully ignored.

## Options

### `--project-dir`

Alternative location of the project directory containing a `Mabo.toml` file.

By default, the current directory is assumed to be the project directory. This is the root from where the command operates. Therefore, using it has the same effect as moving to the project directory and executing the command without it.
21 changes: 21 additions & 0 deletions book/src/reference/cli/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Command Line Interface

To ease and support the development of Mabo schema files, a variety of tools are available. These are all bundled together into a single binary that can be utilized through the terminal.

The following pages describe the details of each available command.

## Installation

Available installation methods are described on the [installation](../../guide/installation#command-line-interface) page of the user guide.

## Global options

These options are available to all commands, when invoking the plain application or using any of the sub-commands described in the following pages.

### `-h`, `--help`

Print the help text for the program or command, explaining each argument and option available. This is in fact the same information as available here.

### `-V`, `--version`

Print the version of the program.
26 changes: 26 additions & 0 deletions book/src/reference/cli/init.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
editLink: false
lastUpdated: false
---

# mabo init

- Aliases: `i`, `initialize`

Initialize a new project.

## Arguments

### `PATH`

Alternative path were the project should be generated.

By default, the current directory is assumed to be the to-be project directory. This is where the `Mabo.toml` file will be placed to mark it as project. Therefore, the path must point to a directory, not a file.

## Options

### `--name`

Name of the project. If omitted, the name is derived from the current working directory.

This is used as the project name in the `Mabo.toml` file to give it a unique identifier. It must only be unique within the project (in case it has multiple projects).
1 change: 0 additions & 1 deletion book/src/reference/cli/lint.md

This file was deleted.

8 changes: 8 additions & 0 deletions book/src/reference/generators/doc.md
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
# Documentation

The `doc` generator does not generate source code, but instead documentation for a Mabo project. It interprets comments as [Markdown](https://daringfireball.net/projects/markdown/) and renders static pages for each element.

This generator is not available as a standalone binary but instead available through the Mabo command line interface with the [mabo doc](../cli/doc) command.

## Hosting

The documentation output consists of static files that can be hosted by any static file host. A common and easy way is to use **GitHub Pages**.
2 changes: 2 additions & 0 deletions book/src/reference/generators/go.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Go

[runtime library](https://github.com/dnaka91/mabo-go)
17 changes: 17 additions & 0 deletions book/src/reference/generators/index.md
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
# Generators

Code generators are the part of Mabo that turn the schema into actual source code that can be consumed by projects.

The sub-sections describe details for all the officially supported generators. These are all written in Rust, but these are not limited to one language.

The mabo compiler can output the parsed schemas in [JSON](https://www.json.org/json-en.html), a data format very common and widespread. Therefore, generators can be written in any language, consume the output and turn it into source code.

## How generators work

Each generator is usually paired with a runtime library to make the generated code work. This handles the low-level workings of the format like encoding individual values.

How a generator is invoked depends on the language. For example:

- Go projects call a binary to generate the code and include the output directly in the repository.
- Java projects use a Gradle plugin to generate the data structures on the fly.
- JavaScript and TypeScript projects use a bundler plugin to generate the data structures.
- Rust projects use a `build.rs` build script file to generate the data structures.
2 changes: 2 additions & 0 deletions book/src/reference/generators/kotlin.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Kotlin

[runtime library](https://github.com/dnaka91/mabo-kt)
2 changes: 2 additions & 0 deletions book/src/reference/generators/python.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Python

[runtime library](https://github.com/dnaka91/mabo-py)
2 changes: 2 additions & 0 deletions book/src/reference/generators/typescript.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Typescript

[runtime library](https://github.com/dnaka91/mabo-ts)
85 changes: 85 additions & 0 deletions crates/mabo-cli/examples/markdown.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! Helper that renders all the CLI sub-commands and arguments into Markdown files for the book.
//!
//! Should be run whenever there are changes to the `src/cli.rs` file to reflect the changes in the
//! book accordingly.

use std::{fmt::Write, fs, path::Path};

use anyhow::{Context, Result};
use clap::CommandFactory;

use self::cli::Cli;

#[allow(dead_code)]
#[path = "../src/cli.rs"]
mod cli;

fn main() -> Result<()> {
let base = concat!(env!("CARGO_MANIFEST_DIR"), "/../../book/src/reference/cli/");
let base = Path::new(base).canonicalize()?;

let cmd = Cli::command();
for sub in cmd.get_subcommands() {
let mut buf = "---\n".to_owned();
writeln!(&mut buf, "editLink: false")?;
writeln!(&mut buf, "lastUpdated: false")?;
writeln!(&mut buf, "---")?;

writeln!(&mut buf, "\n# {} {}", cmd.get_name(), sub.get_name())?;

for (i, alias) in sub.get_visible_aliases().enumerate() {
if i == 0 {
write!(&mut buf, "\n- Aliases: ")?;
} else {
write!(&mut buf, ", ")?;
}
write!(&mut buf, "`{alias}`")?;
}

if sub.get_visible_aliases().next().is_some() {
writeln!(&mut buf)?;
}

if let Some(about) = sub.get_long_about() {
writeln!(&mut buf, "\n{about}")?;
} else if let Some(about) = sub.get_about() {
writeln!(&mut buf, "\n{about}.")?;
}

writeln!(&mut buf, "\n## Arguments")?;
for arg in sub.get_positionals() {
writeln!(
&mut buf,
"\n### `{}`",
arg.get_value_names()
.context("no value name for positional arg")?[0]
)?;

if let Some(help) = arg.get_long_help() {
writeln!(&mut buf, "\n{help}")?;
} else if let Some(help) = arg.get_help() {
writeln!(&mut buf, "\n{help}.")?;
}
}

writeln!(&mut buf, "\n## Options")?;
for arg in sub.get_opts() {
match (arg.get_long(), arg.get_short()) {
(Some(long), Some(short)) => writeln!(&mut buf, "\n### `-{short}`, `--{long}`"),
(Some(long), None) => writeln!(&mut buf, "\n### `--{long}`"),
(None, Some(short)) => writeln!(&mut buf, "\n### `-{short}`"),
(None, None) => continue,
}?;

if let Some(help) = arg.get_long_help() {
writeln!(&mut buf, "\n{help}")?;
} else if let Some(help) = arg.get_help() {
writeln!(&mut buf, "\n{help}.")?;
}
}

fs::write(base.join(format!("{}.md", sub.get_name())), buf)?;
}

Ok(())
}
68 changes: 60 additions & 8 deletions crates/mabo-cli/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,106 @@
use std::path::PathBuf;

use clap::{Args, Parser, Subcommand};
use clap::{Args, Parser, Subcommand, ValueHint};

/// Command line interface to manage and support Mabo schema projects.
#[derive(Parser)]
#[command(about, author, version, propagate_version = true)]
#[command(name = "mabo", about, author, version, propagate_version = true)]
pub struct Cli {
#[command(subcommand)]
pub cmd: Option<Command>,
}

#[derive(Subcommand)]
pub enum Command {
#[command(alias = "initialize")]
/// Initialize a new project.
#[command(visible_aliases = ["i", "initialize"])]
Init(InitArgs),
/// Check that a project or set of files are valid schemas.
///
/// This involves first checking each schema individually to be parseable, then run various
/// lints over it and finally resolve any external schema types. In case any of the steps fail
/// an error will be returned.
#[command(visible_aliases = ["c"])]
Check(CheckArgs),
#[command(alias = "format")]
/// Format a project or set of files.
#[command(visible_aliases = ["f", "format"])]
Fmt(FmtArgs),
#[command(alias = "document")]
/// Generate documentation for a project.
#[command(visible_aliases = ["d", "document"])]
Doc(DocArgs),
}

/// Arguments for the [`Command::Init`] subcommand.
#[derive(Args)]
pub struct InitArgs {
/// Name of the project. If omitted, the name is derived from the current working directory.
///
/// This is used as the project name in the `Mabo.toml` file to give it a unique identifier. It
/// must only be unique within the project (in case it has multiple projects).
#[arg(long)]
pub name: Option<String>,
/// Alternative path were the project should be generated.
///
/// By default, the current directory is assumed to be the to-be project directory. This is
/// where the `Mabo.toml` file will be placed to mark it as project. Therefore, the path must
/// point to a directory, not a file.
#[arg(value_hint = ValueHint::DirPath)]
pub path: Option<PathBuf>,
}

/// Arguments for the [`Command::Check`] subcommand.
#[derive(Args)]
pub struct CheckArgs {
#[arg(long)]
/// Alternative location of the project directory containing a `Mabo.toml` file.
///
/// By default, the current directory is assumed to be the project directory. This is the root
/// from where the command operates. Therefore, using it has the same effect as moving to the
/// project directory and executing the command without it.
#[arg(long, value_hint = ValueHint::DirPath)]
pub project_dir: Option<PathBuf>,
/// Loose list of glob patterns for files that should be checked instead of a project.
///
/// Using this will disable the loading of a project and instead locate the files from the glob
/// patterns, then treat them as one single set. The files will be treated as a single project
/// but the `Mabo.toml` file is fully ignored.
#[arg(conflicts_with = "project_dir")]
pub files: Vec<String>,
}

/// Arguments for the [`Command::Fmt`] subcommand.
#[derive(Args)]
pub struct FmtArgs {
#[arg(long)]
/// Alternative location of the project directory containing a `Mabo.toml` file.
///
/// By default, the current directory is assumed to be the project directory. This is the root
/// from where the command operates. Therefore, using it has the same effect as moving to the
/// project directory and executing the command without it.
#[arg(long, value_hint = ValueHint::DirPath)]
pub project_dir: Option<PathBuf>,
/// Loose list of glob patterns for files that should be formatted instead of a project.
///
/// Using this will disable the loading of a project and instead locate the files from the glob
/// patterns, then treat them as one single set. The files will be treated as a single project
/// but the `Mabo.toml` file is fully ignored.
#[arg(conflicts_with = "project_dir")]
pub files: Vec<String>,
}

/// Arguments for the [`Command::Doc`] subcommand.
#[derive(Args)]
pub struct DocArgs {
#[arg(long)]
/// Alternative location of the project directory containing a `Mabo.toml` file.
///
/// By default, the current directory is assumed to be the project directory. This is the root
/// from where the command operates. Therefore, using it has the same effect as moving to the
/// project directory and executing the command without it.
#[arg(long, value_hint = ValueHint::DirPath)]
pub project_dir: Option<PathBuf>,
/// Directory where the documentation files are written to.
///
/// Note that this directory will be overwritten without confirmation. Any existing files will
/// be replaced, but the directory is not fully cleared beforehand. That means any unrelated
/// files not having the same name as any documentation file, will remain.
pub out_dir: PathBuf,
}

Expand Down

0 comments on commit a1474d9

Please sign in to comment.