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 = [ ...@@ -8947,6 +8947,22 @@ dependencies = [
"winapi 0.3.9", "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]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.2" version = "1.1.2"
...@@ -9374,9 +9390,9 @@ version = "1.6.3" ...@@ -9374,9 +9390,9 @@ version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 1.0.0",
"digest 0.10.3", "digest 0.10.3",
"rand 0.7.3", "rand 0.8.4",
"static_assertions", "static_assertions",
] ]
...@@ -9415,6 +9431,56 @@ dependencies = [ ...@@ -9415,6 +9431,56 @@ dependencies = [
"static_assertions", "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]] [[package]]
name = "unicase" name = "unicase"
version = "2.6.0" version = "2.6.0"
...@@ -10159,6 +10225,7 @@ dependencies = [ ...@@ -10159,6 +10225,7 @@ dependencies = [
"scale-info", "scale-info",
"serde", "serde",
"serde_json", "serde_json",
"tera",
"tokio", "tokio",
"version-compare", "version-compare",
"version_check", "version_check",
......
...@@ -29,3 +29,4 @@ serde_json = "1.0" ...@@ -29,3 +29,4 @@ serde_json = "1.0"
tokio = { version = "1.15.0", features = ["macros"] } tokio = { version = "1.15.0", features = ["macros"] }
version_check = "0.9.2" version_check = "0.9.2"
version-compare = "0.0.11" 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 @@ ...@@ -17,15 +17,88 @@
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use codec::Decode; use codec::Decode;
use scale_info::form::PortableForm; use scale_info::form::PortableForm;
use serde::Serialize;
use std::{ use std::{
fs::File, fs::File,
io::{Read, Write}, io::{Read, Write},
}; };
use tera::Tera;
// consts
const CALLS_DOC_FILEPATH: &str = "docs/api/runtime-calls.md"; 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>; 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 { enum CallCategory {
Disabled, Disabled,
Inherent, Inherent,
...@@ -81,65 +154,7 @@ impl CallCategory { ...@@ -81,65 +154,7 @@ impl CallCategory {
} }
} }
#[derive(Clone)] /// generate runtime calls documentation
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(),
}
}
}
pub(super) fn gen_calls_doc() -> Result<()> { pub(super) fn gen_calls_doc() -> Result<()> {
// Read metadata // Read metadata
let mut file = std::fs::File::open("resources/metadata.scale") let mut file = std::fs::File::open("resources/metadata.scale")
...@@ -192,7 +207,9 @@ fn get_calls_from_metadata_v14( ...@@ -192,7 +207,9 @@ fn get_calls_from_metadata_v14(
Ok(pallets) Ok(pallets)
} }
/// use template to render markdown file with runtime calls documentation
fn print_runtime_calls(pallets: RuntimeCalls) -> String { fn print_runtime_calls(pallets: RuntimeCalls) -> String {
// init variables
let mut user_calls_counter = 0; let mut user_calls_counter = 0;
let user_calls_pallets: RuntimeCalls = pallets let user_calls_pallets: RuntimeCalls = pallets
.iter() .iter()
...@@ -245,109 +262,24 @@ fn print_runtime_calls(pallets: RuntimeCalls) -> String { ...@@ -245,109 +262,24 @@ fn print_runtime_calls(pallets: RuntimeCalls) -> String {
}) })
.collect(); .collect();
let mut output = String::new(); // compile template
let tera = match Tera::new(TEMPLATES_GLOB) {
output.push_str("# Runtime calls\n\n"); Ok(t) => t,
output.push_str("Calls are categorized according to the dispatch origin they require:\n\n"); Err(e) => {
output.push_str( println!("Parsing error(s): {}", e);
r#"1. User calls: the dispatch origin for this kind of call must be Signed by ::std::process::exit(1);
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
} }
};
fn print_call_details(call: &Call) -> String { // fills tera context for rendering
let mut output = String::new(); let mut context = tera::Context::new();
output.push_str(&format!("### Index\n\n`{}`\n\n", call.index)); context.insert("user_calls_counter", &user_calls_counter);
output.push_str(&format!( context.insert("user_calls_pallets", &user_calls_pallets);
"### Documentation\n\n{}\n\n", context.insert("root_calls_counter", &root_calls_counter);
call.docs context.insert("root_calls_pallets", &root_calls_pallets);
.iter() context.insert("disabled_calls_counter", &disabled_calls_counter);
.take_while(|line| !line.starts_with("# <weight>")) context.insert("disabled_calls_pallets", &disabled_calls_pallets);
.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
}
fn print_call_params(call_params: &[CallParam]) -> String { tera.render("runtime-calls.md", &context)
call_params .expect("template error")
.iter()
.map(|param| param.name.clone())
.collect::<Vec<_>>()
.join(", ")
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment