use std::fs::File;
#[allow(unused)]
fn main() {
println!("cargo:rerun-if-changed=src");
println!("cargo:rerun-if-changed=build.rs");
let doc_file_path = std::env::var("OUT_DIR").unwrap() + "/rhai-fs-docs.md";
let mut doc_file = File::create(doc_file_path).expect("create doc file");
#[cfg(feature = "metadata")]
doc_gen::generate_doc(&mut doc_file);
}
#[cfg(feature = "metadata")]
mod doc_gen {
use rhai::{plugin::*, Engine};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::io::Write;
mod pkg {
include!("src/path.rs");
include!("src/file.rs");
include!("src/dir.rs");
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Metadata {
pub functions: Option<Vec<DocFunc>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[allow(non_snake_case)]
struct DocFunc {
pub access: String,
pub baseHash: u128,
pub fullHash: u128,
pub name: String,
pub namespace: String,
pub numParams: usize,
pub params: Option<Vec<HashMap<String, String>>>,
pub signature: String,
pub returnType: Option<String>,
pub docComments: Option<Vec<String>>,
}
impl DocFunc {
pub fn fmt_signature(&self) -> String {
self.signature
.replace(" -> Result<", " -> ")
.replace(", Box<EvalAltResult>>", "")
.replace("&mut ", "")
.replace(" -> ()", "")
.replace("ImmutableString", "String")
}
pub fn fmt_doc_comments(&self) -> Option<String> {
self.docComments.clone().map(|dc| {
dc.join("\n")
.replace("/// ", "")
.replace("///", "")
.replace("/**", "")
.replace("**/", "")
.replace("**/", "")
})
}
}
fn fmt_fn_name(mut name: &str, mut signature: String) -> (&str, &str, String) {
let mut prefix = "";
if name.starts_with("get$") {
signature.drain(0..4);
name = &name[4..];
prefix = "property get ";
}
if name.starts_with("set$") {
signature.drain(0..4);
name = &name[4..];
prefix = "property set ";
}
if name == "index$get" {
signature.drain(0..6);
name = "get";
prefix = "indexer ";
}
if name == "index$set" {
signature.drain(0..6);
name = "set";
prefix = "indexer ";
}
(prefix, name, signature)
}
pub fn generate_doc(writer: &mut impl Write) {
let mut engine = Engine::new();
let mut fs_module = Module::new();
combine_with_exported_module!(&mut fs_module, "rhai_fs_path", pkg::path_functions);
combine_with_exported_module!(&mut fs_module, "rhai_file_path", pkg::file_functions);
combine_with_exported_module!(&mut fs_module, "rhai_dir_path", pkg::dir_functions);
engine.register_global_module(fs_module.into());
let json_fns = engine.gen_fn_metadata_to_json(false).unwrap();
let v: Metadata = serde_json::from_str(&json_fns).unwrap();
let function_list = v.functions.as_ref().map_or(&[][..], Vec::as_slice);
let mut indented = false;
for (idx, function) in function_list.iter().enumerate() {
let name: &str = &function.name;
if !name.starts_with("anon$") {
let signature = function.fmt_signature();
let comments = function.fmt_doc_comments().unwrap_or_default();
let (prefix, name, signature) = fmt_fn_name(name, signature);
if idx < function_list.len() - 1 {
if name == function_list[idx + 1].name && !indented {
writeln!(writer, "## {prefix}`{}`", name.to_owned())
.expect("Cannot write to {doc_file}");
indented = true;
}
}
if indented {
writeln!(writer, "### {prefix}`{signature}`\n\n{comments}")
.expect("Cannot write to {doc_file}");
} else {
writeln!(writer, "## {prefix}`{signature}`\n{comments}")
.expect("Cannot write to {doc_file}");
}
if idx != 0 && idx < function_list.len() - 1 {
if name == function_list[idx - 1].name && name != function_list[idx + 1].name {
indented = false;
}
}
}
}
}
}