Skip to content
Snippets Groups Projects
Commit 477fe3da authored by Hugo Trentesaux's avatar Hugo Trentesaux
Browse files

use tera templates to generate runtime calls doc

parent 3b84a169
No related branches found
No related tags found
No related merge requests found
......@@ -8947,6 +8947,22 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "tera"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d4685e72cb35f0eb74319c8fe2d3b61e93da5609841cde2cb87fcc3bea56d20"
dependencies = [
"globwalk",
"lazy_static",
"pest",
"pest_derive",
"regex",
"serde",
"serde_json",
"unic-segment",
]
[[package]]
name = "termcolor"
version = "1.1.2"
......@@ -9374,9 +9390,9 @@ version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"digest 0.10.3",
"rand 0.7.3",
"rand 0.8.4",
"static_assertions",
]
......@@ -9415,6 +9431,56 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-segment"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23"
dependencies = [
"unic-ucd-segment",
]
[[package]]
name = "unic-ucd-segment"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicase"
version = "2.6.0"
......@@ -10159,6 +10225,7 @@ dependencies = [
"scale-info",
"serde",
"serde_json",
"tera",
"tokio",
"version-compare",
"version_check",
......
......@@ -29,3 +29,4 @@ serde_json = "1.0"
tokio = { version = "1.15.0", features = ["macros"] }
version_check = "0.9.2"
version-compare = "0.0.11"
tera = { version = "1", default-features = false }
\ No newline at end of file
There are **{{ calls_counter }}** {{ category_name }} calls from **{{ pallets | length }}** pallets.
{% for pallet in pallets -%}
### {{ pallet.name }} - {{ pallet.index }}
{% for call in pallet.calls -%}
#### {{ call.name }} - {{ call.index }}
<details><summary><code>{{ call.name }}(
{%- for param in call.params -%}
{{ param.name }}{% if loop.last != true %}, {% endif %}
{%- endfor -%}
)</code></summary>
```rust
{% for param in call.params -%}
{{ param.name }}: {{ param.type_name }}
{% endfor -%}
```
</details>
{{ call.documentation }}
{% endfor -%}
{% endfor -%}
# Runtime calls
Calls are categorized according to the dispatch origin they require:
1. **User calls**: the dispatch origin for this kind of call must be signed by
the transactor. This is the only call category that can be submitted with an extrinsic.
1. **Root calls**: This kind of call requires a special origin that can only be invoked
through on-chain governance mechanisms.
1. **Inherent calls**: This kind of call is invoked by the author of the block itself
(usually automatically by the node).
1. **Disabled calls**: These calls are disabled for different reasons (to be documented).
{% set pallets = user_calls_pallets -%}
{% set calls_counter = user_calls_counter -%}
{% set category_name = "user" -%}
## User calls
{% include "runtime-calls-category.md" %}
{% set pallets = root_calls_pallets -%}
{% set calls_counter = root_calls_counter -%}
{% set category_name = "root" -%}
## Root calls
{% include "runtime-calls-category.md" %}
{% set pallets = disabled_calls_pallets %}
{% set calls_counter = disabled_calls_counter %}
{% set category_name = "disabled" %}
## Disabled calls
{% include "runtime-calls-category.md" -%}
......@@ -17,15 +17,88 @@
use anyhow::{bail, Context, Result};
use codec::Decode;
use scale_info::form::PortableForm;
use serde::Serialize;
use std::{
fs::File,
io::{Read, Write},
};
use tera::Tera;
// consts
const CALLS_DOC_FILEPATH: &str = "docs/api/runtime-calls.md";
const TEMPLATES_GLOB: &str = "xtask/res/templates/*.md";
// define structs and implementations
type RuntimeCalls = Vec<Pallet>;
#[derive(Clone, Serialize)]
struct Pallet {
index: u8,
name: String,
calls: Vec<Call>,
}
impl Pallet {
fn new(
index: u8,
name: String,
scale_type_def: &scale_info::TypeDef<PortableForm>,
) -> Result<Self> {
if let scale_info::TypeDef::Variant(calls_enum) = scale_type_def {
Ok(Self {
index,
name,
calls: calls_enum.variants().iter().map(Into::into).collect(),
})
} else {
bail!("Invalid metadata")
}
}
}
#[derive(Clone, Serialize)]
struct Call {
documentation: String,
index: u8,
name: String,
params: Vec<CallParam>,
}
impl From<&scale_info::Variant<PortableForm>> for Call {
fn from(variant: &scale_info::Variant<PortableForm>) -> Self {
Self {
documentation: variant
.docs()
.to_vec()
.iter()
.take_while(|line| !line.starts_with("# <weight>"))
.cloned()
.collect::<Vec<_>>()
.join("\n"),
index: variant.index(),
name: variant.name().to_owned(),
params: variant.fields().iter().map(Into::into).collect(),
}
}
}
#[derive(Clone, Serialize)]
struct CallParam {
name: String,
type_name: String,
}
impl From<&scale_info::Field<PortableForm>> for CallParam {
fn from(field: &scale_info::Field<PortableForm>) -> Self {
Self {
name: field.name().cloned().unwrap_or_default(),
type_name: field.type_name().cloned().unwrap_or_default(),
}
}
}
enum CallCategory {
Disabled,
Inherent,
......@@ -81,65 +154,7 @@ impl CallCategory {
}
}
#[derive(Clone)]
struct Pallet {
index: u8,
name: String,
calls: Vec<Call>,
}
impl Pallet {
fn new(
index: u8,
name: String,
scale_type_def: &scale_info::TypeDef<PortableForm>,
) -> Result<Self> {
if let scale_info::TypeDef::Variant(calls_enum) = scale_type_def {
Ok(Self {
index,
name,
calls: calls_enum.variants().iter().map(Into::into).collect(),
})
} else {
bail!("Invalid metadata")
}
}
}
#[derive(Clone)]
struct Call {
docs: Vec<String>,
index: u8,
name: String,
params: Vec<CallParam>,
}
impl From<&scale_info::Variant<PortableForm>> for Call {
fn from(variant: &scale_info::Variant<PortableForm>) -> Self {
Self {
docs: variant.docs().to_vec(),
index: variant.index(),
name: variant.name().to_owned(),
params: variant.fields().iter().map(Into::into).collect(),
}
}
}
#[derive(Clone)]
struct CallParam {
name: String,
type_name: String,
}
impl From<&scale_info::Field<PortableForm>> for CallParam {
fn from(field: &scale_info::Field<PortableForm>) -> Self {
Self {
name: field.name().cloned().unwrap_or_default(),
type_name: field.type_name().cloned().unwrap_or_default(),
}
}
}
/// generate runtime calls documentation
pub(super) fn gen_calls_doc() -> Result<()> {
// Read metadata
let mut file = std::fs::File::open("resources/metadata.scale")
......@@ -192,7 +207,9 @@ fn get_calls_from_metadata_v14(
Ok(pallets)
}
/// use template to render markdown file with runtime calls documentation
fn print_runtime_calls(pallets: RuntimeCalls) -> String {
// init variables
let mut user_calls_counter = 0;
let user_calls_pallets: RuntimeCalls = pallets
.iter()
......@@ -245,109 +262,24 @@ fn print_runtime_calls(pallets: RuntimeCalls) -> String {
})
.collect();
let mut output = String::new();
output.push_str("# Runtime calls\n\n");
output.push_str("Calls are categorized according to the dispatch origin they require:\n\n");
output.push_str(
r#"1. User calls: the dispatch origin for this kind of call must be Signed by
the transactor. This is the only call category that can be submitted with an extrinsic.
"#,
);
output.push_str(
r#"1. Root calls: This kind of call requires a special origin that can only be invoked
through on-chain governance mechanisms.
"#,
);
output.push_str(
r#"1. Inherent calls: This kind of call is invoked by the author of the block itself
(usually automatically by the node).
"#,
);
output.push_str(
r#"1. Disabled calls: These calls are disabled for different reasons (to be documented).
"#,
);
output.push_str("\n\n## User calls\n\n");
output.push_str(&print_calls_category(
user_calls_counter,
"user",
user_calls_pallets,
));
output.push_str("\n\n## Root calls\n\n");
output.push_str(&print_calls_category(
root_calls_counter,
"root",
root_calls_pallets,
));
output.push_str("\n\n## Disabled calls\n\n");
output.push_str(&print_calls_category(
disabled_calls_counter,
"disabled",
disabled_calls_pallets,
));
output
}
fn print_calls_category(calls_counter: usize, category_name: &str, pallets: Vec<Pallet>) -> String {
let mut output = String::new();
output.push_str(&format!(
"There are **{}** {} calls organized in **{}** pallets.\n",
calls_counter,
category_name,
pallets.len()
));
for pallet in pallets {
output.push_str(&format!("\n### {}: {}\n\n", pallet.index, pallet.name));
for call in pallet.calls {
output.push_str(&format!(
"<details><summary>{}: {}({})</summary>\n<p>\n\n{}</p>\n</details>\n\n",
call.index,
call.name,
print_call_params(&call.params),
print_call_details(&call),
));
}
}
output
// compile template
let tera = match Tera::new(TEMPLATES_GLOB) {
Ok(t) => t,
Err(e) => {
println!("Parsing error(s): {}", e);
::std::process::exit(1);
}
};
fn print_call_details(call: &Call) -> String {
let mut output = String::new();
output.push_str(&format!("### Index\n\n`{}`\n\n", call.index));
output.push_str(&format!(
"### Documentation\n\n{}\n\n",
call.docs
.iter()
.take_while(|line| !line.starts_with("# <weight>"))
.cloned()
.collect::<Vec<_>>()
.join("\n")
));
if !call.params.is_empty() {
output.push_str("### Types of parameters\n\n```rust\n");
output.push_str(
&call
.params
.iter()
.map(|param| format!("{}: {}", param.name, param.type_name))
.collect::<Vec<_>>()
.join(",\n"),
);
output.push_str("\n```\n\n");
}
output
}
// fills tera context for rendering
let mut context = tera::Context::new();
context.insert("user_calls_counter", &user_calls_counter);
context.insert("user_calls_pallets", &user_calls_pallets);
context.insert("root_calls_counter", &root_calls_counter);
context.insert("root_calls_pallets", &root_calls_pallets);
context.insert("disabled_calls_counter", &disabled_calls_counter);
context.insert("disabled_calls_pallets", &disabled_calls_pallets);
fn print_call_params(call_params: &[CallParam]) -> String {
call_params
.iter()
.map(|param| param.name.clone())
.collect::<Vec<_>>()
.join(", ")
tera.render("runtime-calls.md", &context)
.expect("template error")
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment