mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Generate full wiki from typedefs file
This commit is contained in:
parent
32bca9dde5
commit
ec040e420e
4 changed files with 154 additions and 7 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -808,6 +808,7 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"console",
|
"console",
|
||||||
"full_moon",
|
"full_moon",
|
||||||
|
"futures-util",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lune",
|
"lune",
|
||||||
"regex",
|
"regex",
|
||||||
|
|
|
@ -331,6 +331,7 @@ declare process: {
|
||||||
|
|
||||||
The third argument, `options`, can be passed as a dictionary of options to give to the child process.
|
The third argument, `options`, can be passed as a dictionary of options to give to the child process.
|
||||||
The available options inside of the `options` dictionary are:
|
The available options inside of the `options` dictionary are:
|
||||||
|
|
||||||
* `cwd` - The current working directory for the process
|
* `cwd` - The current working directory for the process
|
||||||
* `env` - Extra environment variables to give to the process
|
* `env` - Extra environment variables to give to the process
|
||||||
* `shell` - Whether to run in a shell or not - set to `true` to run using the default shell, or a string to run using a specific shell
|
* `shell` - Whether to run in a shell or not - set to `true` to run using the default shell, or a string to run using a specific shell
|
||||||
|
|
|
@ -26,6 +26,7 @@ tokio.workspace = true
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
|
|
||||||
anyhow = "1.0.68"
|
anyhow = "1.0.68"
|
||||||
|
futures-util = "0.3.26"
|
||||||
regex = "1.7.1"
|
regex = "1.7.1"
|
||||||
serde_yaml = "0.9.17"
|
serde_yaml = "0.9.17"
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,166 @@
|
||||||
use std::{fmt::Write, path::PathBuf};
|
use std::{collections::HashMap, fmt::Write, path::PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
use futures_util::future::try_join_all;
|
||||||
use tokio::fs::{create_dir_all, write};
|
use tokio::fs::{create_dir_all, write};
|
||||||
|
|
||||||
use super::definitions::DefinitionsTree;
|
use super::definitions::{DefinitionsItem, DefinitionsItemKind, DefinitionsTree};
|
||||||
|
|
||||||
pub const GENERATED_COMMENT_TAG: &str = "@generated with lune-cli";
|
const GENERATED_COMMENT_TAG: &str = "<!-- @generated with lune-cli -->";
|
||||||
|
const CATEGORY_NONE: &str = "uncategorized";
|
||||||
|
|
||||||
pub async fn generate_from_type_definitions(contents: &str) -> Result<()> {
|
pub async fn generate_from_type_definitions(contents: &str) -> Result<()> {
|
||||||
let tree = DefinitionsTree::from_type_definitions(contents)?;
|
let tree = DefinitionsTree::from_type_definitions(contents)?;
|
||||||
|
let mut dirs_to_write = Vec::new();
|
||||||
|
let mut files_to_write = Vec::new();
|
||||||
// Create the wiki dir at the repo root
|
// Create the wiki dir at the repo root
|
||||||
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
let path_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
.join("../../")
|
.join("../../")
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
create_dir_all(&root.join("wiki"))
|
let path_wiki_dir = path_root.join("wiki");
|
||||||
.await
|
dirs_to_write.push(path_wiki_dir.clone());
|
||||||
.context("Failed to create wiki dir")?;
|
// Sort doc items into subcategories based on globals
|
||||||
|
let mut api_reference: HashMap<&str, Vec<DefinitionsItem>> = HashMap::new();
|
||||||
|
for top_level_item in tree
|
||||||
|
.children()
|
||||||
|
.iter()
|
||||||
|
.filter(|top_level| top_level.is_exported())
|
||||||
|
{
|
||||||
|
match top_level_item.kind() {
|
||||||
|
DefinitionsItemKind::Table => {
|
||||||
|
let category_name = top_level_item
|
||||||
|
.get_name()
|
||||||
|
.context("Missing name for top-level doc item")?;
|
||||||
|
let category = match api_reference.contains_key(category_name) {
|
||||||
|
true => api_reference.get_mut(category_name).unwrap(),
|
||||||
|
false => {
|
||||||
|
api_reference.insert(category_name, vec![]);
|
||||||
|
api_reference.get_mut(category_name).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
category.push(top_level_item.clone());
|
||||||
|
}
|
||||||
|
DefinitionsItemKind::Function => {
|
||||||
|
let category = match api_reference.contains_key(CATEGORY_NONE) {
|
||||||
|
true => api_reference.get_mut(CATEGORY_NONE).unwrap(),
|
||||||
|
false => {
|
||||||
|
api_reference.insert(CATEGORY_NONE, vec![]);
|
||||||
|
api_reference.get_mut(CATEGORY_NONE).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
category.push(top_level_item.clone());
|
||||||
|
}
|
||||||
|
_ => unimplemented!("Globals other than tables and functions are not yet implemented"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generate our api reference folder
|
||||||
|
let path_api_ref = path_wiki_dir.join("api-reference");
|
||||||
|
dirs_to_write.push(path_api_ref.clone());
|
||||||
|
// Generate files for all subcategories
|
||||||
|
for (category_name, category_items) in api_reference {
|
||||||
|
if category_items.len() == 1 {
|
||||||
|
let item = category_items.first().unwrap();
|
||||||
|
let path = path_api_ref.join(category_name).with_extension("md");
|
||||||
|
let mut contents = String::new();
|
||||||
|
write!(contents, "{GENERATED_COMMENT_TAG}\n\n")?;
|
||||||
|
generate_markdown_documentation(&mut contents, item)?;
|
||||||
|
files_to_write.push((path, post_process_docs(contents)));
|
||||||
|
} else {
|
||||||
|
let path_subcategory = path_api_ref.join(category_name);
|
||||||
|
dirs_to_write.push(path_subcategory.clone());
|
||||||
|
for item in category_items {
|
||||||
|
let item_name = item
|
||||||
|
.get_name()
|
||||||
|
.context("Missing name for subcategory doc item")?;
|
||||||
|
let path = path_subcategory.join(item_name).with_extension("md");
|
||||||
|
let mut contents = String::new();
|
||||||
|
write!(contents, "{GENERATED_COMMENT_TAG}\n\n")?;
|
||||||
|
generate_markdown_documentation(&mut contents, &item)?;
|
||||||
|
files_to_write.push((path, post_process_docs(contents)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write all dirs and files only when we know generation was successful
|
||||||
|
let futs_dirs = dirs_to_write
|
||||||
|
.drain(..)
|
||||||
|
.map(create_dir_all)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let futs_files = files_to_write
|
||||||
|
.drain(..)
|
||||||
|
.map(|(path, contents)| write(path, contents))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
try_join_all(futs_dirs).await?;
|
||||||
|
try_join_all(futs_files).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_markdown_documentation(contents: &mut String, item: &DefinitionsItem) -> Result<()> {
|
||||||
|
match item.kind() {
|
||||||
|
DefinitionsItemKind::Table => {
|
||||||
|
write!(
|
||||||
|
contents,
|
||||||
|
"\n# {}\n",
|
||||||
|
item.get_name().context("Table is missing a name")?
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
DefinitionsItemKind::Property => {
|
||||||
|
write!(
|
||||||
|
contents,
|
||||||
|
"\n### `{}`\n",
|
||||||
|
item.get_name().context("Property is missing a name")?
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
DefinitionsItemKind::Function => {
|
||||||
|
write!(
|
||||||
|
contents,
|
||||||
|
"\n### `{}`\n",
|
||||||
|
item.get_name().context("Function is missing a name")?
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
DefinitionsItemKind::Description => {
|
||||||
|
write!(
|
||||||
|
contents,
|
||||||
|
"\n{}\n",
|
||||||
|
item.get_value().context("Description is missing a value")?
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let descriptions = item
|
||||||
|
.children()
|
||||||
|
.iter()
|
||||||
|
.filter(|child| child.is_description())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let properties = item
|
||||||
|
.children()
|
||||||
|
.iter()
|
||||||
|
.filter(|child| child.is_property())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let functions = item
|
||||||
|
.children()
|
||||||
|
.iter()
|
||||||
|
.filter(|child| child.is_function())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for description in descriptions {
|
||||||
|
generate_markdown_documentation(contents, description)?;
|
||||||
|
}
|
||||||
|
if !properties.is_empty() {
|
||||||
|
write!(contents, "\n\n---\n\n## Properties\n\n")?;
|
||||||
|
}
|
||||||
|
for property in properties {
|
||||||
|
generate_markdown_documentation(contents, property)?;
|
||||||
|
}
|
||||||
|
if !functions.is_empty() {
|
||||||
|
write!(contents, "\n\n---\n\n## Functions\n\n")?;
|
||||||
|
}
|
||||||
|
for function in functions {
|
||||||
|
generate_markdown_documentation(contents, function)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_process_docs(contents: String) -> String {
|
||||||
|
contents.replace("\n\n\n", "\n\n")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue