diff --git a/book/.vitepress/config.mts b/book/.vitepress/config.mts index f145604..7705654 100644 --- a/book/.vitepress/config.mts +++ b/book/.vitepress/config.mts @@ -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" }, diff --git a/book/src/guide/installation.md b/book/src/guide/installation.md index de7f3d5..673f21e 100644 --- a/book/src/guide/installation.md +++ b/book/src/guide/installation.md @@ -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. diff --git a/book/src/reference/cli/check.md b/book/src/reference/cli/check.md index 2c909ee..e2ae702 100644 --- a/book/src/reference/cli/check.md +++ b/book/src/reference/cli/check.md @@ -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. diff --git a/book/src/reference/cli/doc.md b/book/src/reference/cli/doc.md index 56306b3..11df11b 100644 --- a/book/src/reference/cli/doc.md +++ b/book/src/reference/cli/doc.md @@ -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. diff --git a/book/src/reference/cli/fmt.md b/book/src/reference/cli/fmt.md index 8e57d52..18ff635 100644 --- a/book/src/reference/cli/fmt.md +++ b/book/src/reference/cli/fmt.md @@ -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. diff --git a/book/src/reference/cli/index.md b/book/src/reference/cli/index.md index e69de29..6add321 100644 --- a/book/src/reference/cli/index.md +++ b/book/src/reference/cli/index.md @@ -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. diff --git a/book/src/reference/cli/init.md b/book/src/reference/cli/init.md new file mode 100644 index 0000000..05fe60d --- /dev/null +++ b/book/src/reference/cli/init.md @@ -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). diff --git a/book/src/reference/cli/lint.md b/book/src/reference/cli/lint.md deleted file mode 100644 index 9951adf..0000000 --- a/book/src/reference/cli/lint.md +++ /dev/null @@ -1 +0,0 @@ -# mabo lint diff --git a/book/src/reference/generators/doc.md b/book/src/reference/generators/doc.md index 25f8d45..527e2e8 100644 --- a/book/src/reference/generators/doc.md +++ b/book/src/reference/generators/doc.md @@ -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**. diff --git a/book/src/reference/generators/go.md b/book/src/reference/generators/go.md index 452b575..8cc9f01 100644 --- a/book/src/reference/generators/go.md +++ b/book/src/reference/generators/go.md @@ -1 +1,3 @@ # Go + +[runtime library](https://github.com/dnaka91/mabo-go) diff --git a/book/src/reference/generators/index.md b/book/src/reference/generators/index.md index 7d5fe7a..d69d652 100644 --- a/book/src/reference/generators/index.md +++ b/book/src/reference/generators/index.md @@ -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. diff --git a/book/src/reference/generators/kotlin.md b/book/src/reference/generators/kotlin.md index 554a99e..3399d1c 100644 --- a/book/src/reference/generators/kotlin.md +++ b/book/src/reference/generators/kotlin.md @@ -1 +1,3 @@ # Kotlin + +[runtime library](https://github.com/dnaka91/mabo-kt) diff --git a/book/src/reference/generators/python.md b/book/src/reference/generators/python.md index 4193ef4..7634a01 100644 --- a/book/src/reference/generators/python.md +++ b/book/src/reference/generators/python.md @@ -1 +1,3 @@ # Python + +[runtime library](https://github.com/dnaka91/mabo-py) diff --git a/book/src/reference/generators/typescript.md b/book/src/reference/generators/typescript.md index 42c9775..a29610e 100644 --- a/book/src/reference/generators/typescript.md +++ b/book/src/reference/generators/typescript.md @@ -1 +1,3 @@ # Typescript + +[runtime library](https://github.com/dnaka91/mabo-ts) diff --git a/crates/mabo-cli/examples/markdown.rs b/crates/mabo-cli/examples/markdown.rs new file mode 100644 index 0000000..b6a7444 --- /dev/null +++ b/crates/mabo-cli/examples/markdown.rs @@ -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(()) +} diff --git a/crates/mabo-cli/src/cli.rs b/crates/mabo-cli/src/cli.rs index 5ac7063..b442df2 100644 --- a/crates/mabo-cli/src/cli.rs +++ b/crates/mabo-cli/src/cli.rs @@ -1,9 +1,10 @@ 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, @@ -11,44 +12,95 @@ pub struct Cli { #[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, + /// 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, } /// 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, + /// 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, } /// 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, + /// 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, } /// 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, + /// 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, }